代码之家  ›  专栏  ›  技术社区  ›  Dario

特殊传递属性

  •  3
  • Dario  · 技术社区  · 7 年前

    我最近一直在为复杂的HOC和如何只通过其中定义的新道具而不是任何其他道具而挣扎。

    const withSession = (WrappedComponent) => {
    
      class SessionProvider extends React.PureComponent {
        constructor(props) {
          super(props);
          this.login = this.login.bind(this);
        }
    
        login() {
          console.log('login'); // this will dispatch some action
          // this.props.dispatch... 
        }
    
        render() {
    
          return (
            <WrappedComponent
              doLogin={this.login}
              {...this.props} 
            />
          );
        }
      }
    
      const mapStateToProps = null;
    
      function mapDispatchToProps(dispatch) {
        return {
          dispatch,
        };
      }
    
     const withConnect = connect(mapStateToProps, mapDispatchToProps);
    
     return compose(
        withConnect,
        withRouter,
      )(injectIntl(SessionProvider));
    };
    

    在这里 SessionProvider dispatch injectIntl props . 但是,我不想把这些道具传递给包装的组件。我们的想法是 HOC,它有一些API调用,但只扩展了包装好的组件 login 我注意到如果你继续 {...this.props} ,包装的组件也将获得所有 由我不想通过的HOC使用。 this.props 通过更改渲染方法:

    render() {
      const { dispatch, intl, ...otherProps } = this.props;
      return <WrappedComponent doLogin={this.login} { ...otherProps} />;
    }
    

    dispach intl 道具,那些不是通过HOC传递的。

    我做的有什么不对吗?有更好的方法吗?我遗漏了什么吗?

    2 回复  |  直到 7 年前
        1
  •  1
  •   n1stre    7 年前

    你所做的没有错。使用HOC时,道具名称冲突是一个已知问题。所以,据我所知,最好的选择是 Render Props 有助于保持组件 render 尽可能的声明性。对于您的情况,请考虑以下内容:

    class Session extends React.PureComponent {
      constructor(props) {
        super(props);
        this.login = this.login.bind(this);
      }
    
      login() {
        console.log("login"); // this will dispatch some action
        // this.props.dispatch...
      }
    
      // ...
    
      render() {
        return (
          <React.Fragment>
            {this.props.children({
              doLogin: this.login
              doLogout: this.logout
              // ...
            })}
          </React.Fragment>
        );
      }
    }
    
    // ...
    
    return compose(
      withConnect,
      withRouter
    )(injectIntl(Session));
    

    并从其他组件中使用:

    // ...
    render() {
      return (
    
        <Session>
          {({ doLogin, doLogout }) => (
            <React.Fragment>
              <SomeComponent doLogin={doLogin} />
              <button onClick={doLogout}>Logout</button>
            </React.Fragment>
          )}
        </Session>
    
      )
    }
    

    有一个很有前途的计划 Hooks Proposal 提供于 v16.7.0-α . 我还不太熟悉它们,但是它们倾向于更有效地解决组件的可重用性。

        2
  •  0
  •   abhirathore2006    7 年前

    export const REACT_STATICS = {
      childContextTypes: true,
      contextTypes: true,
      defaultProps: true,
      displayName: true,
      getDefaultProps: true,
      mixins: true,
      propTypes: true,
      type: true
    };
    
    export const KNOWN_STATICS = {
      name: true,
      length: true,
      prototype: true,
      caller: true,
      arguments: true,
      arity: true
    };
    
    export function hoistStatics(targetComponent, sourceComponent) {
      var keys = Object.getOwnPropertyNames(sourceComponent);
      for (var i = 0; i < keys.length; ++i) {
        const key = keys[i];
        if (!REACT_STATICS[key] && !KNOWN_STATICS[key]) {
          try {
            targetComponent[key] = sourceComponent[key];
          } catch (error) {}
        }
      }
      return targetComponent;
    }
    
    
    // in HOC
    const hoistedSessionProvider = hoistStatics(SessionProvider, WrappedComponent);
    
    // use hoistedSessionProvider in compose