Skip to main content

优化扁平列表配置

条款

¥Terms

  • 虚拟化列表:FlatList 背后的组件(React Native 对 Virtual List 概念的实现。)

    ¥VirtualizedList: The component behind FlatList (React Native's implementation of the Virtual List concept.)

  • 内存消耗:有关列表的多少信息存储在内存中,这可能会导致应用崩溃。

    ¥Memory consumption: How much information about your list is being stored in memory, which could lead to an app crash.

  • 响应能力:应用响应交互的能力。例如,低响应性是指当你触摸某个组件时,它需要等待一段时间才能响应,而不是按预期立即响应。

    ¥Responsiveness: Application ability to respond to interactions. Low responsiveness, for instance, is when you touch on a component and it waits a bit to respond, instead of responding immediately as expected.

  • 空白区域:当 VirtualizedList 无法足够快地渲染你的项目时,你可以输入列表的一部分,其中包含显示为空白的未渲染组件。

    ¥Blank areas: When VirtualizedList can't render your items fast enough, you may enter a part of your list with non-rendered components that appear as blank space.

  • Viewport:渲染为像素的内容的可见区域。

    ¥Viewport: The visible area of content that is rendered to pixels.

  • Window:应安装项目的区域,通常比视口大得多。

    ¥Window: The area in which items should be mounted, which is generally much larger than the viewport.

属性

¥Props

以下是有助于提高 FlatList 性能的属性列表:

¥Here are a list of props that can help to improve FlatList performance:

removeClippedSubviews

类型默认
布尔值错误的

如果是 true,则视口之外的视图将从原生视图层次结构中分离。

¥If true, views that are outside of the viewport are detached from the native view hierarchy.

属性:通过从原生渲染和绘图遍历中排除视口之外的视图,可以减少主线程上花费的时间,从而降低丢帧的风险。

¥Pros: This reduces time spent on the main thread, and thus reduces the risk of dropped frames, by excluding views outside of the viewport from the native rendering and drawing traversals.

缺点:请注意,此实现可能存在错误,例如缺少内容(主要在 iOS 上观察到),特别是当你使用转换和/或绝对定位执行复杂的操作时。另请注意,这不会节省大量内存,因为视图不会被释放,只是被分离。

¥Cons: Be aware that this implementation can have bugs, such as missing content (mainly observed on iOS), especially if you are doing complex things with transforms and/or absolute positioning. Also note this does not save significant memory because the views are not deallocated, only detached.

maxToRenderPerBatch

类型默认
数字10

这是一个可以通过 FlatList 传递的 VirtualizedList 属性。这控制每批渲染的项目数量,这是每个滚动上渲染的下一个项目块。

¥It is a VirtualizedList prop that can be passed through FlatList. This controls the amount of items rendered per batch, which is the next chunk of items rendered on every scroll.

属性:设置更大的数字意味着滚动时视觉空白区域更少(增加填充率)。

¥Pros: Setting a bigger number means less visual blank areas when scrolling (increases the fill rate).

缺点:每批处理的项目越多,意味着 JavaScript 执行时间越长,可能会阻塞其他事件处理(例如按下),从而损害响应能力。

¥Cons: More items per batch means longer periods of JavaScript execution potentially blocking other event processing, like presses, hurting responsiveness.

updateCellsBatchingPeriod

类型默认
数字50

虽然 maxToRenderPerBatch 告诉每批渲染的项目数量,但设置 updateCellsBatchingPeriod 告诉 VirtualizedList 批渲染之间的延迟(以毫秒为单位)(组件渲染窗口项目的频率)。

¥While maxToRenderPerBatch tells the amount of items rendered per batch, setting updateCellsBatchingPeriod tells your VirtualizedList the delay in milliseconds between batch renders (how frequently your component will be rendering the windowed items).

属性:例如,将此属性与 maxToRenderPerBatch 结合使用,你可以在频率较低的批次中渲染更多的项目,或者在频率较高的批次中渲染更少的项目。

¥Pros: Combining this prop with maxToRenderPerBatch gives you the power to, for example, render more items in a less frequent batch, or less items in a more frequent batch.

缺点:频率较低的批次可能会导致空白区域,频率较高的批次可能会导致响应问题。

¥Cons: Less frequent batches may cause blank areas, More frequent batches may cause responsiveness issues.

initialNumToRender

类型默认
数字10

要渲染的初始项目数量。

¥The initial amount of items to render.

属性:定义覆盖每个设备屏幕的精确项目数量。这对于初始渲染来说可以是一个巨大的性能提升。

¥Pros: Define precise number of items that would cover the screen for every device. This can be a big performance boost for the initial render.

缺点:设置较低的 initialNumToRender 可能会导致空白区域,尤其是当它太小而无法在初始渲染时覆盖视口时。

¥Cons: Setting a low initialNumToRender may cause blank areas, especially if it's too small to cover the viewport on initial render.

windowSize

类型默认
数字21

这里传递的数字是一个测量单位,其中 1 相当于你的视口高度。默认值为 21(上方 10 个视口,下方 10 个视口,中间 1 个)。

¥The number passed here is a measurement unit where 1 is equivalent to your viewport height. The default value is 21 (10 viewports above, 10 below, and one in between).

属性:windowSize 越大,滚动时看到空白区域的机会就越小。另一方面,较小的 windowSize 将导致同时安装的项目较少,从而节省内存。

¥Pros: Bigger windowSize will result in less chance of seeing blank space while scrolling. On the other hand, smaller windowSize will result in fewer items mounted simultaneously, saving memory.

缺点:对于更大的 windowSize,你将有更多的内存消耗。对于较低的 windowSize,你将有更大的机会看到空白区域。

¥Cons: For a bigger windowSize, you will have more memory consumption. For a lower windowSize, you will have a bigger chance of seeing blank areas.

列出项目

¥List items

以下是有关列表项组件的一些提示。它们是你列表的核心,因此需要速度快。

¥Below are some tips about list item components. They are the core of your list, so they need to be fast.

使用基本组件

¥Use basic components

组件越复杂,渲染速度就越慢。尽量避免在列表项中出现大量逻辑和嵌套。如果你在应用中多次重复使用此列表项组件,请仅为你的大列表创建一个组件,并使其具有尽可能少的逻辑和嵌套。

¥The more complex your components are, the slower they will render. Try to avoid a lot of logic and nesting in your list items. If you are reusing this list item component a lot in your app, create a component only for your big lists and make them with as little logic and nesting as possible.

使用轻组件

¥Use light components

组件越重,渲染速度就越慢。避免使用沉重的图片(对列表项使用裁剪版本或缩略图,尽可能小)。与你的设计团队交谈,在列表中使用尽可能少的效果、交互和信息。在你的商品详细信息中显示它们。

¥The heavier your components are, the slower they render. Avoid heavy images (use a cropped version or thumbnail for list items, as small as possible). Talk to your design team, use as little effects and interactions and information as possible in your list. Show them in your item's detail.

使用 memo()

¥Use memo()

React.memo() 创建一个记忆组件,仅当传递给组件的 props 发生变化时才会重新渲染。我们可以使用这个函数来优化 FlatList 中的组件。

¥React.memo() creates a memoized component that will be re-rendered only when the props passed to the component change. We can use this function to optimize the components in the FlatList.

import React, {memo} from 'react';
import {View, Text} from 'react-native';

const MyListItem = memo(
({title}: {title: string}) => (
<View>
<Text>{title}</Text>
</View>
),
(prevProps, nextProps) => {
return prevProps.title === nextProps.title;
},
);

export default MyListItem;

在此示例中,我们确定仅当标题更改时才应重新渲染 MyListItem。我们将比较函数作为第二个参数传递给 React.memo(),以便仅当指定的 prop 更改时才重新渲染组件。如果比较函数返回 true,则组件将不会被重新渲染。

¥In this example, we have determined that MyListItem should be re-rendered only when the title changes. We passed the comparison function as the second argument to React.memo() so that the component is re-rendered only when the specified prop is changed. If the comparison function returns true, the component will not be re-rendered.

使用缓存的优化图片

¥Use cached optimized images

你可以使用社区包(例如 @DylanVann 中的 react-native-fast-image)来获得更高性能的图片。列表中的每个图片都是 new Image() 实例。它到达 loaded 钩子的速度越快,你的 JavaScript 线程再次释放的速度就越快。

¥You can use the community packages (such as react-native-fast-image from @DylanVann) for more performant images. Every image in your list is a new Image() instance. The faster it reaches the loaded hook, the faster your JavaScript thread will be free again.

使用 getItemLayout

¥Use getItemLayout

如果所有列表项组件都具有相同的高度(或宽度,对于水平列表),则提供 getItemLayout 属性将消除 FlatList 管理异步布局计算的需要。这是一种非常理想的优化技术。

¥If all your list item components have the same height (or width, for a horizontal list), providing the getItemLayout prop removes the need for your FlatList to manage async layout calculations. This is a very desirable optimization technique.

如果你的组件具有动态尺寸并且你确实需要性能,请考虑询问你的设计团队是否会考虑重新设计以提高性能。

¥If your components have dynamic size and you really need performance, consider asking your design team if they may think of a redesign in order to perform better.

使用 keyExtractor 或 key

¥Use keyExtractor or key

你可以将 keyExtractor 设置为 FlatList 组件。该属性用于缓存并作为 React key 来跟踪项目重新排序。

¥You can set the keyExtractor to your FlatList component. This prop is used for caching and as the React key to track item re-ordering.

你还可以在项目组件中使用 key 属性。

¥You can also use a key prop in your item component.

避免在 renderItem 上使用匿名函数

¥Avoid anonymous function on renderItem

对于功能组件,将 renderItem 函数移到返回的 JSX 之外。另外,请确保将其封装在 useCallback 钩子中,以防止每次渲染时都重新创建它。

¥For functional components, move the renderItem function outside of the returned JSX. Also, ensure that it is wrapped in a useCallback hook to prevent it from being recreated each render.

对于类组件,将 renderItem 函数移到渲染函数之外,这样每次调用渲染函数时它就不会重新创建自身。

¥For class componenents, move the renderItem function outside of the render function, so it won't recreate itself each time the render function is called.

const renderItem = useCallback(({item}) => (
<View key={item.key}>
<Text>{item.title}</Text>
</View>
), []);

return (
// ...

<FlatList data={items} renderItem={renderItem} />;
// ...
);