1.元件props的資料類型校驗
# https://react.docschina.org/docs/typechecking-with-proptypes.html
例子:
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
// 指定 props 的類型:
Greeting.propTypes = {
name: PropTypes.string
};
// 指定 props 的預設值
Greeting.defaultProps = {
name: 'Stranger'
};
# PropTypes常見類型
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// 你可以将屬性聲明為 JS 原生類型,預設情況下
// 這些屬性都是可選的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// 任何可被渲染的元素(包括數字、字元串、元素或數組)
// (或 Fragment) 也包含這些類型。
optionalNode: PropTypes.node,
// 一個 React 元素。
optionalElement: PropTypes.element,
// 一個 React 元素類型(即,MyComponent)。
optionalElementType: PropTypes.elementType,
// 你也可以聲明 prop 為類的執行個體,這裡使用
// JS 的 instanceof 操作符。
optionalMessage: PropTypes.instanceOf(Message),
// 你可以讓你的 prop 隻能是特定的值,指定它為
// 枚舉類型。
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// 一個對象可以是幾種類型中的任意一個類型
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// 可以指定一個數組由某一類型的元素組成
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
optionalArrayOf: PropTypes.oneOfType(PropTypes.number, PropTypes.string),
// 可以指定一個對象由某一類型的值組成
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// 可以指定一個對象由特定的類型值組成
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// 你可以在任何 PropTypes 屬性後面加上 `isRequired` ,確定
// 這個 prop 沒有被提供時,會列印警告資訊。
requiredFunc: PropTypes.func.isRequired,
// 任意類型的必需資料
requiredAny: PropTypes.any.isRequired,
// 你可以指定一個自定義驗證器。它在驗證失敗時應傳回一個 Error 對象。
// 請不要使用 `console.warn` 或抛出異常,因為這在 `oneOfType` 中不會起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 你也可以提供一個自定義的 `arrayOf` 或 `objectOf` 驗證器。
// 它應該在驗證失敗時傳回一個 Error 對象。
// 驗證器将驗證數組或對象中的每個值。驗證器的前兩個參數
// 第一個是數組或對象本身
// 第二個是他們目前的鍵。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};
2.Props、State與render函數
# 當元件的Props或者State發生改變時,render函數就會重新執行。即資料驅動頁面更新渲染
# 當父元件的render函數被運作時,它的子元件的render都會被重新執行一次。
例子:當<input/>的值發生改變,則觸發函數changeInputHandle去更新state的inputVal的值,再觸發render函數将inputVal的值更新到<input/>的value中
import React from 'react';
// 引入子元件
import TodoItem from './TodoItem';
class App extends React.Component {
// 元件構造器
constructor(props) {
super(props);
this.state = {
todoItems: ['vue', 'react', 'node'],
inputVal: ''
};
// 給方法綁定this的指向作用域,方法内的this指向本元件
this.changeInputHandle = this.changeInputHandle.bind(this);
}
changeInputHandle(e) {
const val = e.target.value;
this.setState({
inputVal: val
});
}
render() {
return (
<div className='App'>
<div>
<input type='text' value={this.state.inputVal} onChange={this.changeInputHandle}/>
<button onClick={this.addHandle}>add</button>
</div>
<ul>
{
this.state.todoItems.map((item, index) => {
return (
<TodoItem
key={index}
index={index}
content={item}/>
)
})
}
</ul>
</div>
)
}
}
export default App;
# 子元件TodoItem
import React from 'react';
class TodoItem extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
// this.props發生改變,則會重新執行render函數
render() {
const {content} = this.props
return (
<li>{content}</li>
)
}
}
export default TodoItem;
3.React的虛拟DOM
react虛拟DOM就是一個js對象,用來描述真實DOM。
例子:
真實DOM:<div>hello</div>
虛拟DOM: ['div',{...屬性},'hello']
return( <div>hello</div> ) 等同于 return React.createElement('div',{},'hello')
資料渲染過程:
1. state 初始化資料
2. jsx 定義渲染模闆,render(){return(<div>hello</div>)}
3. 生成虛拟DOM,虛拟DOM就是一個js對象,用來描述真實DOM
虛拟DOM: ['div',{...屬性},'hello']
4. 資料+模闆,結合生成真實DOM, 顯示頁面(即元件被第一次建立時調用構造函數)
真實DOM:<div>hello</div>
5. state 發生改變,即this.setState({name: 'react'}),setState是異步函數,提高渲染性能
6. 資料+模闆,結合生成新的虛拟DOM(比生成真實DOM提高了性能)
新虛拟DOM: ['div',['react']]
7. 新虛拟DOM與舊虛拟DOM做比較,找出不同的地方(Diff算法)
8. 直接操作舊的DOM, 将新改變的内容資料更新渲染出來
render(){
// jsx->虛拟DOM(jsx對象)->真實DOM
return( <div>hello</div> )
}
# setState是異步函數,setState({},callback) 或者 setState(fun,callback)
this.setState(
()=>{
return{}
},
()=>{}
)
4.React的虛拟DOM中的Diff算法(同層級比對)
循環渲染清單,key={},不要使用index值作為key,因為Diff算法同層級比對是根據key值來判斷。
5.React元件的生命周期
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPnJGb4dlWyYlMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLzMDO4ATOzEjM1EDNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
# 父元件
import React, {Component} from 'react';
import TodoItem from './TodoItem';
class App extends Component {
// 構造函數,元件建構時被執行,隻在元件被首次建立時執行一次
constructor(props) {
console.log('1.父元件-構造函數')
super(props);
// 初始化元件資料
this.state = {
todoItems: ['vue', 'react', 'node'],
inputVal: ''
};
this.changeInputHandle = this.changeInputHandle.bind(this);
}
// 元件将要渲染挂載到頁面,在render函數執行之前
componentWillMount() {
// 隻在元件被首次建立時執行一次
console.log('2.父元件-componentWillMount')
}
// 元件已挂載到頁面,一般在此執行ajax資料請求
componentDidMount() {
// 隻在元件被首次建立時執行一次
console.log('4.父元件-componentDidMount')
}
// 當state資料發生改變時(即this.setState),執行詢問是否允許更新元件
shouldComponentUpdate(nextProps, nextState, nextContext) {
// true為允許更新元件, false為不允許
console.log('5.父元件-shouldComponentUpdate')
if (nextProps.inputVal !== this.state.inputVal) {
return true
}
return false
}
// 元件将要更新
componentWillUpdate(nextProps, nextState, nextContext) {
console.log('6.父元件-componentWillUpdate')
}
// 元件更新完成
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('7.父元件-componentWillUpdate')
}
// props改變時(父傳子),執行詢問是否更新元件,true允許,false不允許
// 用于子元件中,當父傳子的資料發生改變時,是否允許更新子元件
// 被執行的條件:父傳子的資料發生改變,同時子元件已經在父元件中(不是第一次構造渲染)
componentWillReceiveProps(nextProps, nextContext) {
console.log('8.父元件-componentWillReceiveProps')
return true
}
// 元件将要銷毀
componentWillUnmount() {
console.log('9.父元件-componentWillUnmount')
}
// input輸入值發生改變時更新state
changeInputHandle(e) {
const val = e.target.value;
this.setState(() => {
return {
inputVal: val
}
});
}
// state或者props改變都會執行render函數
render() {
console.log('3.父元件-render')
return (
<div className='App'>
<div>
<input type='text' value={this.state.inputVal} onChange={this.changeInputHandle}/>
</div>
<ul>
{
this.state.todoItems.map((item, index) => {
return (
<TodoItem key={index} content={item}/>
)
})
}
</ul>
</div>
)
}
}
export default App;
# 子元件
import React from 'react';
class TodoItem extends React.Component {
// 構造函數,元件建構時被執行,隻在元件被首次建立時執行一次
constructor(props) {
console.log('1.子元件-構造函數')
super(props);
this.state = {};
}
// 元件将要渲染挂載到頁面,在render函數執行之前
componentWillMount() {
// 隻在元件被首次建立時執行一次
console.log('2.子元件-componentWillMount')
}
// 元件已挂載到頁面,一般在此執行ajax資料請求
componentDidMount() {
// 隻在元件被首次建立時執行一次
console.log('4.子元件-componentDidMount')
}
// 當state資料發生改變時(即this.setState),執行詢問是否允許更新元件
shouldComponentUpdate(nextProps, nextState, nextContext) {
// true為允許更新元件, false為不允許
console.log('5.子元件-shouldComponentUpdate')
if (nextProps.inputVal !== this.state.inputVal) {
return true
}
return false
}
// 元件将要更新
componentWillUpdate(nextProps, nextState, nextContext) {
console.log('6.子元件-componentWillUpdate')
}
// 元件更新完成
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('7.子元件-componentWillUpdate')
}
// props改變時(父傳子),執行詢問是否更新元件,true允許,false不允許
// 用于子元件中,當父傳子的資料發生改變時,是否允許更新子元件
// 被執行的條件:父傳子的資料發生改變,同時子元件已經在父元件中(不是第一次構造渲染)
componentWillReceiveProps(nextProps, nextContext) {
console.log('8.子元件-componentWillReceiveProps')
return true
}
// 元件将要銷毀
componentWillUnmount() {
console.log('9.子元件-componentWillUnmount')
}
render() {
console.log('3.子元件-render')
const {content} = this.props;
return (
<li>{content}</li>
)
}
}
export default TodoItem;
6.Mock接口資料模拟
# 使用 Charles 進行接口資料模拟
下載下傳:https://www.charlesproxy.com/download/
使用流程:
1.在本地建立json檔案
2.打開 Charles 工具,tool > map local > 指定接口傳回的json資料