如何使用ES6编写ReactJS高阶组件?

时间:2018-04-27 06:01:33

标签: javascript reactjs high-order-component

我正在尝试使用ES6语法构建一个ReactJS高阶组件。这是我的尝试:

export const withContext = Component =>
    class AppContextComponent extends React.Component {
        render() {
            return (
                <AppContextLoader>
                     <AppContext.Consumer>
                        {context => <Component {...props} context={context} />}
                    </AppContext.Consumer>
               </AppContextLoader>
            );
        }
    };

这里,AppContextLoader从数据库获取上下文并将其提供给上下文,如:

class AppContextLoader extends Component {
  state = {
    user: null,
  };

  componentWillMount = () => {
    let user = databaseProvider.getUserInfo();
    this.setState({
      user: user
      });
  };


  render = () => {
    return (
      <AppContext.Provider value={this.state}>
        {this.props.children}
      </AppContext.Provider>
    );
  };
}

export default AppContextLoader;

用法:

class App extends Component {
    static propTypes = {
         title: PropTypes.string,
         module: PropTypes.string
    }

    render = () => {
        return (
                withContext(
                <Dashboard
                    module={this.props.module}
                    title={this.props.title}
                />
                );

export default App;

由于某些原因,我的包裹组件(Dashboard)没有获得context属性,只有原始属性(titlemodule)。

如何使用ES6语法正确编写HOC?

3 个答案:

答案 0 :(得分:1)

您没有正确使用HOC,您需要传递组件而不是组件实例。从render中调用HOC也是一个糟糕的模式,因为每次渲染都会返回一个新组件,你必须写

const DashboardWithContext = withContext(Dashboard);
class App extends Component {
    render = () => {
        return (
                <DashboardWithContext
                    module={"ADMIN"}
                    title={"MY APP"}
                />
        )
    }
}

export default App;

同样在withContext HOC中,因为返回的组件是一个类,您将访问类似{...this.props}而不是{...props}的道具。但是,因为您不是,所以使用功能组件是有意义的实际上使用生命周期方法

 export const withContext = Component => (props) => (
            <AppContext.Consumer>
                {context => <Component {...props} context={context} />}
            </AppContext.Consumer>
        );

<强> Working Codesandbox

答案 1 :(得分:0)

应改为this.props

<Component {...this.props}

这应该适合你:

render() {
  const props = this.props;
  return (
    <AppContext.Consumer>
      {context => <Component {...props} context={context} />}
    </AppContext.Consumer>
  );
}

答案 2 :(得分:0)

您遇到一些问题:

  1. 您没有正确使用Context API-创建上下文是为了使用Provider与一个或多个Consumers共享一个值-您是通过即席创建的新的ProviderConsumer

  2. 在您的示例中,您无需使用Context-将临时用途用于新使用数据-withUserData

  3. 您应该使用this.props而不是道具

  4. 在用法部分,将元素而不是组件传递给hoc

  5. 您没有从withContext

  6. 获得道具

解决方案

export const withUserData = BaseComponent =>
  class AppContextLoader extends Component {
    state = {
      user: null,
    };

    componentWillMount = () => {
      let user = databaseProvider.getUserInfo();
      this.setState({
        user: user
      });
    };


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

和用法:

class App extends Component {
    static propTypes = {
         title: PropTypes.string,
         module: PropTypes.string
    }

    render = () => {
        return (
                  <EnhancedDashboard
                    module={this.props.module}
                    title={this.props.title}
                  />
                );
     }


const EnhancedDashboard = withUserData(Dashboard)

export default App;