title: 传递原始值到列表项以实现记忆化
impact: HIGH
impactDescription: 使 memo() 比较更有效
tags: lists, performance, memo, primitives
传递原始值到列表项以实现记忆化
尽可能只传递原始值(字符串、数字、布尔值)作为 props 给列表项组件。原始值使memo()的浅比较能够正确工作,在值未变化时跳过重渲染。
错误方式(对象 prop 需要深比较):
type User = { id: string; name: string; email: string; avatar: string } const UserRow = memo(function UserRow({ user }: { user: User }) { // memo() 按引用比较 user,而非按值 // 如果父级创建了新的 user 对象,即使数据相同也会重渲染 return <Text>{user.name}</Text> }) renderItem={({ item }) => <UserRow user={item} />}这仍然可以优化,但正确记忆化更困难。
正确方式(原始值 props 启用浅比较):
const UserRow = memo(function UserRow({ id, name, email, }: { id: string name: string email: string }) { // memo() 直接比较每个原始值 // 仅在 id、name 或 email 实际变化时重渲染 return <Text>{name}</Text> }) renderItem={({ item }) => ( <UserRow id={item.id} name={item.name} email={item.email} /> )}只传递需要的内容:
// 错误:只需要 name 时传递了整个 item <UserRow user={item} /> // 正确:只传递组件使用的字段 <UserRow name={item.name} avatarUrl={item.avatar} />对于回调,提升或使用 item ID:
// 错误:内联函数创建新引用 <UserRow name={item.name} onPress={() => handlePress(item.id)} /> // 正确:传递 ID,在子组件内部处理 <UserRow id={item.id} name={item.name} /> const UserRow = memo(function UserRow({ id, name }: Props) { const handlePress = useCallback(() => { // 在此处使用 id }, [id]) return <Pressable onPress={handlePress}><Text>{name}</Text></Pressable> })原始值 props 使记忆化可预测且有效。
注意:如果已启用 React Compiler,则无需使用memo()或useCallback(),但对象引用的问题仍然适用。