簡體   English   中英

如何使React HOC - 高階組件協同工作?

[英]How to make React HOC - High Order Components work together?

我有一個像這樣的小型演示組件:

function MyList({data, uppercaseMe, lowercaseMe}) {
    return <ul>
        {data.map(item =>
            <li>{item} -
                <button onClick={() => uppercaseMe(item)}>Uppercase me!</button>
                <button onClick={() => lowercaseMe(item)}>Lowercase me!</button>
            </li>)}
    </ul>;
}

然后我想用三個HOC來裝飾MyList:

const WithData = (Component) => {
return class extends React.Component {

    constructor(props) {
        super(props);
        this.state= {data:['one', 'two', 'three', 'four', 'five']};
    };

    render() {
        return <Component {...this.props} data={this.state.data} />;
    }
}
};

const WithUppercase = (Component) => {
return class extends React.Component {

    uppercaseMe = (item) => {
        // how to access WithData state from here?
        console.log(item.toUpperCase());
    };

    constructor(props) {
        super(props);
    };

    render() {
        return <Component {...this.props} uppercaseMe={this.uppercaseMe}/>;
    }
 }
};

const WithLowercase = (Component) => {
return class extends React.Component {

    lowercaseMe = (item) => {
        // how to access WithData state from here?
        console.log(item.toLowerCase());
    };

    constructor(props) {
        super(props);
    };

    render() {
        return <Component {...this.props} lowercaseMe={this.lowercaseMe}/>;
    }
 }
};

像這樣:

const ComposedList = WithLowercase(WithUppercase(WithData(MyList)));

不幸的是,我不知道如何在WithLowercase或WithUppercase中更改WithData的狀態。

你如何將一個HOC的狀態暴露給鏈中的另一個HOCS?

您不希望直接公開狀態。 你想要做的是將一個函數作為prop傳遞給包裝組件,以允許你更新狀態。

因此,如果我們使用HOC並添加一些代碼,則創建一個函數來更新其狀態,現在可以將其傳遞給其子組件:

const WithData = (Component) => {
  return class extends React.Component {

      constructor(props) {
          super(props);
          this.state= {data:['one', 'two', 'three', 'four', 'five']};
      }

      update (data) {
        this.setState({ data });
      }

      render() {
          return <Component onUpdate={this.update} {...this.props} data={this.state.data} />;
      }
  }
};

現在,在其中一個子組件中,我們可以使用它:

const WithUppercase = (Component) => {
    return class extends React.Component {

        uppercaseMe = (item) => {
            const itemIndex = this.props.data.indexOf(item);
            const newData = this.props.data.slice();
            newData[itemIndex] = item.toUpperCase();
            this.props.onUpdate(newData); // update WithData state here
        };

        constructor(props) {
            super(props);
        };

        render() {
            // onUpdate function is once again passed to child components
            // implicitly through props if you need to call it again
            return <Component {...this.props} uppercaseMe={this.uppercaseMe}/>;
        }
    }
};

將數據傳遞回組件鏈本質上違背了反應使用的模式,這是數據流的一種方式。 數據下降但永遠不會恢復。 就像@FuriousD所說的那樣,你應該讓lowerCase和upperCase方法可用於鏈中的組件。 您可以使用上下文執行此操作。

“在某些情況下,您希望通過組件樹傳遞數據,而不必在每個級別手動傳遞道具。您可以使用強大的”上下文“API直接在React中執行此操作。”

以下是使用代碼更新版本的示例。

const WithUpperCase = (Component) => {
  class _WithUpperCase extends React.Component {
    getChildContext() {
      return {
        uppercaseMe: this.uppercaseMe,
      }
    }

    uppercaseMe = (item) => {
      return item.toUpperCase()
    };

    render() {
      return <Component {...this.props} />;
    }
  }

  _WithUpperCase.childContextTypes = {
    lowercaseMe: PropTypes.func,
  }

  return _WithUpperCase;
};

const WithLowercase = (Component) => {
  class _WithLowercase extends React.Component {
    getChildContext() {
      return {
        lowercaseMe: this.lowercaseMe,
      }
    }

    lowercaseMe = (item) => {
      return item.toLowerCase()
    };

    render() {
      return <Component {...this.props} />;
    }
  }

  _WithLowercase.childContextTypes = {
    lowercaseMe: PropTypes.func,
  }

  return _WithLowercase;
};

function MyList({ data }, { uppercaseMe, lowercaseMe }) {
  return (
    <ul>
      {
        data.map(item => (
          <li>{item} -
          <button onClick={() => uppercaseMe(item)}>Uppercase me!</button>
            <button onClick={() => lowercaseMe(item)}>Lowercase me!</button>
          </li>
        ))
      }
    </ul>
  );
}

MyList.contextTypes = {
  // Need to import the PropTypes library
  uppercaseMe: PropTypes.func,
  lowercaseMe: PropTypes.func,
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM