React Functional 组件:作为函数调用与作为组件调用

IT技术 javascript reactjs
2021-04-19 09:26:57

假设我有一个功能组件:

const Foo = (props) => ( <div>{props.name}</div> );

直接作为函数调用有什么区别:

const fooParent = () => (
    <div> {Foo({ name: "foo" })} </div>
)

与将其作为组件调用:

const fooParent = () => (
    <div> <Foo name="foo"/> </div>
)

我最感兴趣的是性能影响,React 如何在内部以不同的方式对待它们,也许 React Fiber 中的事情可能会有所不同,我听说功能组件在那里获得了性能提升。

4个回答

将其作为函数调用要快得多,事实上几个月前就有人讨论过这个问题。在这一点上,函数式react组件不能是PureComponents,因此没有真正应用于它们的额外优化。

基本上,如果您可以将功能组件称为消除整个react生命周期的功能。如果您考虑一下,您现在可能正在渲染方法中使用这种技术。考虑一下:

... some component ... 

render() {

  const tabHeaders =<TabHeaders>{this.props.tabs.map(this.renderTabHeader)}</TabHeader>;
  const tabContents = <TabContents>{this.props.tabs.map(this.renderTabContent)}</TabContents>;

  return (<div>
    {this.props.tabsBelow?[tabContents, tabHeaders] : [tabHeaders, tabContents]}
  </div>);
} 

renderTabHeader 方法返回一些react组件,并且可能是功能组件,但在这种情况下只是一些组件类方法。

详细解释见这篇文章:https : //medium.com/missive-app/45-faster-react-functional-components-now-3509a668e69f

另请查看正在执行此操作的 babel 插件:https : //babeljs.io/docs/plugins/transform-react-inline-elements

啊..原来是那篇文章让我问这个问题的XD。因此,还有关于 React Fiber 的部分 - 那篇文章中有一条评论,暗示已经对功能组件进行了优化以使其更快。我想知道这如何影响结果。
2021-05-24 09:26:57
在较新版本的反应中,情况仍然如此吗?
2021-06-06 09:26:57
接近它的正确方法是测量。但总的来说,你几乎不能比没有代码更快。
2021-06-09 09:26:57
你能总结一下为什么把它作为函数调用会更快吗?另外,如果没有缺点,那么为什么不这样做的标准呢?似乎大多数文档都指向您将功能组件称为组件。
2021-06-15 09:26:57
如果您使用钩子,它的行为可能会很奇怪。参见kentcdodds.com/blog/dont-call-a-react-function-component
2021-06-17 09:26:57

所以我实际上遇到了一个用例,在这种用例中,将渲染作为组件而不是函数调用是有益的。使用 React 16,您可以获得错误边界功能。这允许您在组件内引发错误时呈现回退错误 UI。事实证明,如果在函数调用变体中抛出异常,则不会触发componentDidCatch. 它需要在子组件中抛出。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      error: false
    };
  }

  componentDidCatch() {
    this.setState({ error: true});
  }

  render() {
    return this.state.error
      ? "Error :("
      : this.props.children;
  }
}

const renderContent = () => {
  throw new Error();
}

const Content = () => {
  throw new Error();
}

// This will throw exception and not trigger error state
const Foo = () => (
  <ErrorBoundary>
    <div>{renderContent()}</div>
  </ErrorBoundary>
);

// This will trigger the error state
const Bar = () => (
  <ErrorBoundary>
    <div><Content /></div>
  </ErrorBoundary>
);

当然,您可以有更高的错误边界,但只是指出一个特定的用例,您可以选择其中一个。

此外,出于命名目的,将其渲染为组件也很不错。它会在 React 开发工具中显示命名,并且您也可以在进行酶测试时使用该名称作为选择器。

如果直接调用功能组件,实际上是在调用自定义钩子。

例子:

function A() {
  const [state] = useState([])
  return (
    <div>{state}</div>
  )
}

A()
<A />

如果您调用A(),则state挂载在父光纤中,但如果您使用<A />,React 将调用createElement以创建要挂载的新光纤state

实际上,当您将其称为组件时,会创建一个新元素 React.createElement()另一方面,函数被直接调用。所以,这就解释了为什么直接调用你的函数会更快。

但请记住,在某些情况下,直接调用函数可能会导致类似@dmwong2268 在这里介绍的问题,或者像这样的问题