简体   繁体   中英

React Functional component: calling as function vs. as component

Say I have a functional component:

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

What is the difference between calling it directly as a function:

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

versus calling it as a component:

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

I'm mostly interested in performance implications, how React treats them differently internally, and perhaps how things might be different in React Fiber, where I hear functional components got a performance boost.

Calling it as a function is much faster, in fact there was a talk exactly about this few months ago. At this point functional react components can't be PureComponents so no extra optimizations really applied to them.

Basically if you can call functional component as a function that eliminates whole react lifecycle. If you think about it you are probably using this technique inside your render method even right now. Consider this:

... 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 method returns some react components, and could've been functional components but in this case is just some component class method.

See this article for detailed explanation: https://medium.com/missive-app/45-faster-react-functional-components-now-3509a668e69f

Also check out this babel plugin that is doing that:https://babeljs.io/docs/plugins/transform-react-inline-elements

So I actually ran into a use case where it is beneficial to render as a component rather than a function call. With React 16, you get the error boundaries feature. This allows you to render fallback error UIs when an error is thrown within the component. Turns out, if an exception is thrown in the function call variation, it won't trigger componentDidCatch . It needs to be thrown within a child component.

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>
);

Of course, you could have an error boundary higher up, but just pointing out one specific use case where you may choose one of the other.

Also, it's nice to render as component for naming purposes. It will show up named in React dev tools, and also you can use the name as selectors when you do Enzyme testing.

If you call functional component directly, you are calling a custom hook actually.

example:

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

A()
<A />

If you call A() , the state mounts in parent fiber, but if you use <A /> , React will call createElement to create a new fiber on which to mount state .

Actually, when you call it as a component a new element is created with React.createElement() . On the other hand, the function is called directly. So, that explains a little bit why calling your function directly is faster.

But keep in mind, that in some cases calling a function directly may cause problems like the one introduced by @dmwong2268 here, or like this one

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM