在render()函数中定义函数组件是否是反模式?

时间:2018-09-17 16:21:32

标签: javascript reactjs react-native

我想知道它是否是反模式,或者是否以某种方式影响了组件,所以执行以下操作:

render() {
  const MyFuncComponent = ({ prop1, prop2 }) => (
    // code here
  )

  return (
    <div>
      <MyFuncComponent prop1={something} prop2={else} />
    </div>
  )
}

3 个答案:

答案 0 :(得分:6)

是的,这是一个反模式,出于同样的原因,我们不应该在render内使用高阶组件。

Don’t Use HOCs Inside the render Method

React的差异算法(称为对帐)使用组件标识来确定是更新现有子树还是丢弃它并安装新的子树。如果从render返回的组件与先前渲染中的组件相同(===),React通过将子树与新树进行比较来递归更新子树。如果它们不相等,则先前的子树将完全卸载。

通常,您无需考虑这一点。但这对HOC很重要,因为这意味着您无法在组件的render方法中将HOC应用于组件:

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

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

这意味着新组件将出现在React树中(可以使用react-devtools进行探索),但它不会保留任何状态和生命周期方法,例如componentDidMount,{{1 }},componentWillUnmount总是在每个渲染周期被调用。

解决方案

由于我们可能想要动态创建组件的原因可能很多,因此这里有一些常见的解决方案来绕过陷阱。

在外部定义新组件

可以在自己的文件中,也可以直接在父组件的定义上方。将任何变量作为prop传递,而不是使用父组件范围访问值。

useEffect

辅助功能

可以直接在另一个组件内部定义使用一个返回JSX的常规函数​​。它不会在React的树中显示为新组件,只会显示其结果,就像内联一样。

这样,除了您想要的任何其他参数外,我们还可以使用封闭范围中的变量(如以下示例中的const MyFuncComponent = ({ prop1, prop2 }) => <>{/* code here */}</>; const MyComponent = props => ( <div> {props.list.map(({ something, thing }) => ( <MyFuncComponent prop1={something} prop2={thing} /> ))} </div> ); )。

props.itemClass

由于它非常灵活,因此也可以在组件外部定义。

const MyComponent = props => {
  // Looks like a component, but only serves as a function.
  const renderItem = ({ prop1, prop2 }) => (
    <li className={props.itemClass}> {/* <-- param from enclosing scope */}
      {prop1} {prop2} {/* other code */}
    </li>
  );

  return <ul>{props.list.map(renderItem)}</ul>;
};

但是在那一点上,我们应该只定义一个React组件,而不是用一个函数伪造它。 以可预测的方式充分利用React。

内联逻辑

通常在条件或const renderItem = (itemClass, { prop1, prop2 }) => ( <li className={itemClass}> {prop1} {prop2} {/* other code */} </li> ); const MyComponent = props => ( <ul> {props.list.map(item => renderItem(props.itemClass, item))} </ul> ); 回调中内联JSX。

map

如果我们发现自己将这个相同的内联JSX复制粘贴到任何地方,可能是时候将其包装在自己的可重用组件中。

答案 1 :(得分:2)

我认为一般来说,人们避免在render中定义函数,但是根据this blog post,这并不是一个坏习惯。该博客文章重点介绍了在render中定义的内联事件处理函数,但我想它适用于render中定义的任何函数。在渲染器中定义函数意味着每次调用渲染器时都要重新定义它们的开销,但这可能并没有明显的性能差异,具体取决于您的组件。

对于您给出的特定示例,我建议不要在render中定义另一个react组件。如果确实在渲染中定义了任何功能,则它们应与渲染的工作紧密结合。在render内定义另一个组件或添加一堆函数会使您笨拙且难以理解代码在做什么。

答案 2 :(得分:0)

执行此操作之前的问题对

  1. 它使代码更具可读性吗? (取决于50/50)
  2. 它使代码更具可测试性吗? (无法嘲笑,紧密耦合-所以“否”)
  3. 它使代码更灵活吗? (紧密耦合-再次“否”)

我宁愿投票赞成让基本组件通过props获得内部组件。而内部组件是在外部某个地方创建的。您将获得更大的灵活性,由于抽象,代码将更具可读性,并且具有更好的可测试性。