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

在组件渲染中调用高阶组件

  •  2
  • Kayote  · 技术社区  · 6 年前

    有件简单的事情让我的逻辑绊倒了:

    我有一个特别的 AnimateOnLoad 它呈现默认内容(在 react-router )在页面组件中。

    const DefaultLayout = ({ component: Component, ...rest }) => (
    
       <Route
          {...rest}
          render={matchProps => (
             <div className="page-container">
                {AnimateOnLoad(
                   <div className="container">
                      <Head />
                      <Nav />
                      <Component {...matchProps} />
                   </div>
                )}
                <Footer />
             </div>
          )}
       />
    );
    

    这个 animateONLoad hoc如下:

    const AnimateOnLoad = WrappedComponent =>
       class Animator extends Component {
          constructor(props) {
             super(props);
             this.ele = React.createRef();
          }
          componentDidMount() {
             Kute.fromTo(
                this.ele.current,
                { opacity: 0.3 },
                { opacity: 1, duration: 120 }
             ).start();
          }
          render() {
             return (
                <div className="animator" ref={this.ele}>
                   <WrappedComponent {...this.props} />
                </div>
             );
          }
       };
    

    但是,我得到一个错误: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it. ,这对我来说没有意义,因为我要返回一个 Component 来自animateOnLoad();

    谢谢您。

    2 回复  |  直到 6 年前
        1
  •  3
  •   Shubham Khatri    6 年前

    您没有使用 AnimateOnLoad 正确即席。你需要像这样使用它

    const CustomComp = (matchProps) => (
         <div className="container">
              <Head />
              <Nav />
              <Component {...matchProps} />
         </div>
    );
    
    const HOCComponent = AnimateOnLoad(CustomComp)
    
    
    const DefaultLayout = ({ component: Component, ...rest }) => (
    
       <Route
          {...rest}
          render={matchProps => (
             <div className="page-container">
                <HOCComponent {...matchProps}/>
                <Footer />
             </div>
          )}
       />
    );
    
        2
  •  3
  •   Abdul Rauf    6 年前

    你的错误的根本原因是

    如果返回组件而不是<组件,则可能发生这种情况 /gt;

    @Shubhamkhatri的回答将解决您的问题。我想扩大他的回答范围。

    不要在渲染方法中使用hocs

    响应差异算法(称为和解)使用组件 标识以确定它是否应更新现有子树或 扔掉它,装上一个新的。如果组件从返回 渲染与上一次渲染的组件相同(==)。 react通过将子树与新子树进行比较来递归更新子树。 如果它们不相等,则会完全卸载前一个子树。

    render() {
      // A new version of Animate is created on every render
      // Animate1 !== Animate2
      const Animate = AnimateOnLoad(MyComponent);
      // That causes the entire subtree to unmount/remount each time!
      return <Animate />;
    }
    

    请注意,hoc在他的回答中是如何在渲染外部使用的。

    这里的问题不仅仅在于重新安装组件的性能会导致该组件及其所有子组件的状态丢失。

    这就是为什么在组件定义之外应用hocs非常重要,这样生成的组件只创建一次。然后,它的身份将在渲染中保持一致。不管怎样,这通常是你想要的。

    参考文献: https://reactjs.org/docs/higher-order-components.html#dont-use-hocs-inside-the-render-method