开发者问题收集

如何以很少的性能损失包装 React 组件?

2018-05-05
1651

我的团队使用 React MaterialUI 库。为了提供一致的 UI 模式并让我们能够轻松自定义 MaterialUI 的组件,我们将每个 MaterialUI 的组件包装在我们自己的组件中。例如:

const style = {} // our project custom style for ListItemText
const OurListItemText = ({primary, secondary, classes}: Props) => (
  <MuiListItemText
    primary={primary}
    secondary={secondary}
    className={classes.text}
  />
) // we only expose primary and secondary props of the original MuiListItemText.
// Team members are blocked from customising other MUIListItemText's props

export default withStyles(styles)(OurListItemText)

MuiListItemText 是原始 MaterialUI 的组件,而 OurListItemText 是我们的包装器组件。在我们的项目中, 允许使用 OurListItemText

如上面的代码片段所示, OurListItemText 什么也不做,只是将 props 转发给 MuiListItemText 。但是,这在很大程度上影响了性能:

React Flame graph

ListItemText 顶部的栏来自 OurListItemText ,而下面的栏来自 MuiListItemText 。如果我们直接使用 MuiListItemText ,速度可能会快约 50%(我们试过了),当我们有 100 个 ListItemText 时,这一点很明显。删除 withStyles HOC 会有所改善,但效果并不明显。

ListItemText 只是一个例子,我们在其他包装组件上也遇到了类似的性能问题。 (上图中的2个 Typography 是另一对 our-wrapper-component 和 MUI's-original-component)

如何提高那些简单的 props-forwarding-components 的性能?

2个回答

wrapping a React component adds one extra level of full React lifecycle (i.e. the wrapper needs to be mounted). Is it possible to avoid this?

您可以通过避免使用 JSX 并直接调用函数来避免生命周期。
例如。

{Component({ data: 1, children: 'Hello' })}

而不是

<Component data={1}>Hello</Component>

这篇博文 声称他们的测试用例实现了 45% 的速度提升。

不过,这种语法可能不那么易读/易理解。

关于这一点,一些来自 Dan Abramov 的引用问题

We're looking at optimizations like this in the context of Prepack but there's nothing that's going to be immediately useable in the next couple of months. Within a year or two we might have something.

Note that unless you're creating thousands of elements, the performance difference won't be noticeable. Also unless your components are very flat and simple, the "pure win" from this optimization will likely be much less relevant in practice.

我不会等待 Prepack 进行优化,因为时间表不确定,并且最终的优化可能与此不相同。

至于性能改进的意义,这取决于你的项目,唯一确定的方法是亲自尝试并查看改进情况。

Roy Wang
2018-05-09

如果您想要原始性能 - 请不要包装 ListItem,而是编写替换项

列表项源 没有任何额外的依赖项,因此 Ctrl-C、Ctrl-V 都可以使用

然后根据您的需要进行调整,删除不需要的代码等...

这将保证最大可能的性能


缺点 - 支持成本将会增加。

Andrii Muzalevskyi
2018-05-12