天天看點

React知識點

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元件的生命周期

React知識點
# 父元件
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資料