React 高階元件

GarinZhang發表於2018-03-11

React高階元件

本文是學習慕課網 React高階元件課程 的筆記~

一、什麼是React高階元件

高階元件就是接收一個元件作為引數,然後返回一個新的元件。高階元件其實是一個函式,並不只是一個元件。

React 高階元件

二、入門Demo來認識高階元件

1、需求分析

加入有某需求:

React 高階元件

我們對上圖進行元件拆分,可以分為外部modal提示框元件和內部資訊兩個元件。

外部modal元件是不變的,但是內部的內容,我們可能在不同的地方會顯示不同的效果。如下圖。

React 高階元件

所以我們有必要去封裝一個外部的modal提示框元件,去包裹不同的內部元件。

2、專案構建

// 建立一個空專案
create-react-app xxx
複製程式碼

我們新建幾個檔案。

React 高階元件

// A/index.js

import React from 'react';
import './index.css';

// 定義一個函式
// 傳入一個元件作為引數
function A(WrappedComponent) {
  // 返回一個元件
  return class A extends React.Component {
    constructor (props) {
      super(props);
      this.state = {};
    }

    render () {
      return (
        <div className="a-container">
           <div className="header">
             <div className="title">提示</div>
             <div className="close">X</div>
           </div>
           <div>
             <!-- 在這裡使用一下 -->
             <WrappedComponent />
           </div>
         </div>
      )
    }
  }
}

// 丟擲函式
export default A

複製程式碼

A元件就是我們的外部Modal提示框元件。用來包裹我們的內部元件。

我們來實現B元件。

// B/index.js

import React from 'react';
import A from '../A/index.js';
import './index.css';


class B extends React.Component {
    render() {
        return (
            <div className="wrap">
                <img src="https://raw.githubusercontent.com/freya0608/High-order-component/master/src/imgs/B.png" alt="" />
            </div>
        );
    }
}

<!--呼叫A()方法去包裹我們的B元件。-->
export default  A(B);

複製程式碼

最終實現效果為:

React 高階元件

到此一個入門的高階元件例項就ok了。

總結:使用高階元件的方式:

React 高階元件

第一種就是我們上面的方法,第二種是利用裝飾器來實現,具體的配置大家網上可以查到。

現在我們又有了需求,就是B元件的內容,可能決定A元件的標題,所以這時候就需要我們去通過B元件去傳值給A了。

// A/index.js

import React from 'react';
import './index.css';

// 這裡我們返回一個匿名函式,接收傳遞得值
export default (title = '我是標題') => {

  // 然後返回一個函式,這個函式接收子元件 
  return (WrappedComponent) => {
    // 返回我們的外部元件
    return class A extends React.Component {
      constructor (props) {
        super(props);
        this.state = {};
      }

      render () {
        return (
          <div className="a-container">
             <div className="header">
               <!--這裡使用我們傳入的值-->
               <div className="title">{title}</div>
               <div className="close">X</div>
             </div>
             <div>
               <WrappedComponent />
             </div>
           </div>
        )
      }
    }
  }
}
複製程式碼
// B/index.js
import React from 'react';
import A from '../A/index.js';
import './index.css';
class B extends React.Component {
    render() {
        return (
            <div className="wrap">
                <img src="https://raw.githubusercontent.com/freya0608/High-order-component/master/src/imgs/B.png" alt="" />
            </div>
        );
    }
}

<!-- 最主要是這裡 -->
export default  A('提示i')(B);

複製程式碼

這樣我們就實現了B給A元件傳值,來讓A元件能動態的改變某些地方了。

三、代理方式的高階元件

React 高階元件

React 高階元件

認識代理方式的高階元件我們要從 prop、訪問ref、抽取狀態、包裹元件四個部分來認識。

  • props
// A/index

import React from 'react';
import './index.css';

export default (title = '我是標題') => {
  return (WrappedComponent) => {
    return class A extends React.Component {
      constructor (props) {
        super(props);
        this.state = {};
      }

      render () {
        // [1] 首先我們可以獲取到給最外層元件傳遞的props
        const prop = this.props;
        console.log(prop);

        
        return (
          <div className="a-container">
             <div className="header">
               <div className="title">{title}</div>
               <div className="close">X</div>
             </div>
             <div>
               <!--[2] 可以傳遞下去,傳到B元件中-->
               <!--[3] 另外sex是新增的-->
               <WrappedComponent sex={'男'} {...this.props} />
             </div>
           </div>
        )
      }
    }
  }
}

複製程式碼
// B/index.js

import React from 'react';
import A from '../A/index.js';
import './index.css';
class B extends React.Component {
    render() {
        return (
            <div className="wrap">
                <!--[1]在B元件中就可以拿到通過A元件傳來的props-->
                我的姓名: {this.props.name}
                我的性別: {this.props.sex}
                <img src="https://raw.githubusercontent.com/freya0608/High-order-component/master/src/imgs/B.png" alt="" />
            </div>
        );
    }
}


export default  A('提示i')(B);
複製程式碼

在APP中我們可以設定props,傳遞到A元件,再由A元件篩選或者增加props,之後傳給B,這樣在B就能接收到最外層以及A傳遞來的props。同樣由於A是中間層,A有許可權控制B能得到哪些props,也能額外增加一些屬性過去。

<B name={'zjj'}></B>
複製程式碼
  • refs
// A/index

import React from 'react';
import './index.css';

export default (title = '我是標題') => {
  return (WrappedComponent) => {
    return class A extends React.Component {
      constructor (props) {
        super(props);
        this.state = {};
      }
      // [1] 定義一個點選事件
      handleClick = () => {
        this.wref.getName();
      }


      render () {
        const prop = this.props;
        console.log(prop);
        return (
          <div className="a-container">
             <div className="header">
               <div className="title">{title}</div>
               <div className="close">X</div>
             </div>
             <div>
                <!-- 【2】繫結ref -->
               <WrappedComponent ref={ (v) => this.wref = v } sex={'男'} {...this.props} />
             </div>
             <div>
             <!--【3】點選事件觸發處-->
              <button onClick={this.handleClick}>獲取name</button>
             </div>
           </div>
        )
      }
    }
  }
}
複製程式碼

我們在B中定義一個getName方法。那麼通過點選A中的按鈕,就可以呼叫到

B/index

getName = () => {
  console.log('獲取到了name')
}
複製程式碼
  • 抽取狀態
// A.js
import React from 'react';
import './index.css';

export default (title = '我是標題') => {
  return (WrappedComponent) => {
    return class A extends React.Component {
      constructor (props) {
        super(props);
        this.state = {
          value: ''
        };
      }

      // 點選
      handleClick = () => {
        this.wref.getName();
      }

      // [1] 根據輸入設定 val
      handleOnInputChange = (e) => {
        this.setState({
          value: e.target.value
        })
      }

      render () {
        const prop = this.props;
        console.log(prop);
        
        // [2] 設定新的props
        var newProps = {
          value: this.state.value, // 傳入值
          onInput: this.handleOnInputChange // 監聽表單的輸入
        }
        return (
          <div className="a-container">
             <div className="header">
               <div className="title">{title}</div>
               <div className="close">X</div>
             </div>
             <div>
               <WrappedComponent ref={ (v) => this.wref = v } sex={'男'} {...this.props}  {...newProps} />
               // 【3】傳入子元件
             </div>
             <div>
              <button onClick={this.handleClick}>獲取name</button>
             </div>
           </div>
        )
      }
    }
  }
}

複製程式碼
// B/index.js
// 使用傳入的值,這樣便可以將子元件內部的實現抽取出來,放到公共的元件中去,統一管理
<input type="text" value={this.props.value} onInput={this.props.onInput} />
複製程式碼
  • 包裝元件

其實我們上面就是實現了包裹內部元件的效果。

相關文章