优化 React 组件渲染 {🚀}
MobX 速度非常快,通常甚至比 Redux 更快,但以下是一些从 React 和 MobX 中获得最大收益的技巧。大多数技巧适用于一般的 React,并不特定于 MobX。请注意,虽然了解这些模式很重要,但通常即使你完全不担心它们,你的应用程序也会足够快。
只有在性能真正成为问题时才优先考虑性能!
使用许多小型组件
observer
组件将跟踪它们使用的所有值,并在任何值发生变化时重新渲染。因此,你的组件越小,它们需要重新渲染的变更就越小。这意味着你的用户界面的更多部分可以独立于彼此进行渲染。
在专用组件中渲染列表
上面的情况在渲染大型集合时尤其如此。React 在渲染大型集合方面臭名昭著,因为协调器必须在每次集合更改时评估集合生成的组件。因此,建议使用只映射集合并渲染它的组件,并且不渲染其他任何内容。
糟糕的
const MyComponent = observer(({ todos, user }) => (
<div>
{user.name}
<ul>
{todos.map(todo => (
<TodoView todo={todo} key={todo.id} />
))}
</ul>
</div>
))
在上面的列表中,当 user.name
发生更改时,React 将不必要地需要协调所有 TodoView
组件。它们不会重新渲染,但协调过程本身很昂贵。
良好的
const MyComponent = observer(({ todos, user }) => (
<div>
{user.name}
<TodosView todos={todos} />
</div>
))
const TodosView = observer(({ todos }) => (
<ul>
{todos.map(todo => (
<TodoView todo={todo} key={todo.id} />
))}
</ul>
))
不要使用数组索引作为键
不要使用数组索引或任何将来可能发生变化的值作为键。如果需要,为你的对象生成 ID。查看这篇 博客文章。
延迟解除引用值
使用 mobx-react
时,建议尽可能延迟解除引用值。这是因为 MobX 会自动重新渲染解除引用可观察值的组件。如果这发生在你的组件树更深的地方,则需要重新渲染的组件更少。
更慢的
<DisplayName name={person.name} />
更快的
<DisplayName person={person} />
在更快的示例中,name
属性的更改只会触发 DisplayName
重新渲染,而在更慢的示例中,组件的拥有者也必须重新渲染。这样做并没有什么错误,如果拥有组件的渲染足够快(通常是!),那么这种方法效果很好。
函数属性 {🚀}
你可能会注意到,为了延迟解除引用值,你必须创建许多小型观察者组件,其中每个组件都定制为渲染数据中的不同部分,例如
const PersonNameDisplayer = observer(({ person }) => <DisplayName name={person.name} />)
const CarNameDisplayer = observer(({ car }) => <DisplayName name={car.model} />)
const ManufacturerNameDisplayer = observer(({ car }) =>
<DisplayName name={car.manufacturer.name} />
)
如果你有很多形状不同的数据,这很快就会变得很繁琐。另一种方法是使用一个返回你想要 *Displayer
渲染的数据的函数
const GenericNameDisplayer = observer(({ getName }) => <DisplayName name={getName()} />)
然后,你可以像这样使用该组件
const MyComponent = ({ person, car }) => (
<>
<GenericNameDisplayer getName={() => person.name} />
<GenericNameDisplayer getName={() => car.model} />
<GenericNameDisplayer getName={() => car.manufacturer.name} />
</>
)
这种方法将允许 GenericNameDisplayer
在你的应用程序中重复使用,以渲染任何名称,并且你仍然可以将组件重新渲染降至最低。