使用 Hooks 进行 React Native 性能优化

2025-06-09

使用 Hooks 进行 React Native 性能优化

工作还行,但不是那么好?😑。

开发人员很容易就能写出能运行的react-native应用,但性能却并非最佳的 React Native 应用。一段时间以来,我一直在寻找一种方法来编写性能最佳的 React Native 应用。我尝试了所有可能的最佳实践来让应用变得更好。
以下是我收集的一些提升 React Native 应用性能的方法、技巧和窍门🔥。

1. 停止使用内联函数

首先,现在停止使用内联函数调用,React Native 认为具有内联函数的 props 每次都是一个新值,这会导致其子组件中不必要的重新渲染。

解决方案

将所有内联函数移至 const。(以及下一步)

例子:

export default ()=>{
const [childState, setChildState] = useState(0);
return(
<FlatList
renderItem={
({item})=>(
<AwesomeChild {...item} onPress={(number)=>{setChildState(number)}} />
)}
keyExtractor={(item)=>`awesome-child-key-${item.id}`}
/>)
}
export default ()=>{
const [childState, setChildState] = useState(0);
return(
<FlatList
renderItem={
({item})=>(
<AwesomeChild {...item} onPress={(number)=>{setChildState(number)}} />
)}
keyExtractor={(item)=>`awesome-child-key-${item.id}`}
/>)
}

之后✅

export default ()=>{
const [childState, setChildState] = useState(0);
//Moved functions
const awesomeChildListRenderItem = ({item})=>(<AwesomeChild {...item} onPress={(number)=>{setChildState(number)}} />)
const awesomeChildListKeyExtractor = (item)=>(`awesome-child-key-${item.id}`);
return(
<FlatList
renderItem={awesomeChildListRenderItem}
keyExtractor={awesomeChildListKeyExtractor}
/>)
}
export default ()=>{
const [childState, setChildState] = useState(0);
//Moved functions
const awesomeChildListRenderItem = ({item})=>(<AwesomeChild {...item} onPress={(number)=>{setChildState(number)}} />)
const awesomeChildListKeyExtractor = (item)=>(`awesome-child-key-${item.id}`);
return(
<FlatList
renderItem={awesomeChildListRenderItem}
keyExtractor={awesomeChildListKeyExtractor}
/>)
}

那么现在应用程序的性能好多了?嗯!还没有,但我们正在取得一些进展。现在我们使组件更加清晰易读。

2. 正确使用useCallback♻️。

任何用于重新渲染组件的函数,
都不应导致不必要的重新渲染,无论何时,只要你不想,无论在 jsx 元素中使用哪个函数,都可以像上一步所示那样将其调出,并应用我们的 hero hook,useCallback
它会做什么?这也不是本文要讨论的内容,你可以在许多文档和文章中找到。但我将仅展示如何实现它来提升 React-native 的性能。

例子

export default ()=>{
const [childState, setChildState] = useState(0);
//using useCallback
const awesomeChildListRenderItem = useCallback(
({ item }) => (
<AwesomeChild {...item} onPress={(number)=>{setChildState(number)}} />
),[]);
const awesomeChildListKeyExtractor = useCallback( (item) => `awesome-child-key-${item.id}`,[]);
return(
<FlatList
renderItem={awesomeChildListRenderItem}
keyExtractor={awesomeChildListKeyExtractor}
/>
)
}
export default ()=>{
const [childState, setChildState] = useState(0);
//using useCallback
const awesomeChildListRenderItem = useCallback(
({ item }) => (
<AwesomeChild {...item} onPress={(number)=>{setChildState(number)}} />
),[]);
const awesomeChildListKeyExtractor = useCallback( (item) => `awesome-child-key-${item.id}`,[]);
return(
<FlatList
renderItem={awesomeChildListRenderItem}
keyExtractor={awesomeChildListKeyExtractor}
/>
)
}

现在,我们通过应用 hero hook 取得了一些进展。这确保了 FlatList 不会重新渲染,因为它AwesomeChild已被记住,并且没有任何东西可以改变它的值。
你可以从上面的代码中观察到,在我们用 useCallback 包装的旧函数之后紧接着使用了空括号,这是依赖关系,如果函数正在使用任何其他值,则需要使用空括号。

例子

export default ()=>{
//Sates is 0 initially
const [pressCount, setPressCount] = useState(0);
//Function to update last state by +1
const updateButtonPress = useCallback(() => {
setPressCount(pressCount + 1);
}, []);
//Empty dependancy
return(
<Button onPress={updateButtonPress} title="Add 1" />
)
}
export default ()=>{
//Sates is 0 initially
const [pressCount, setPressCount] = useState(0);
//Function to update last state by +1
const updateButtonPress = useCallback(() => {
setPressCount(pressCount + 1);
}, []);
//Empty dependancy
return(
<Button onPress={updateButtonPress} title="Add 1" />
)
}

上面的代码是将 1 添加到其最后一个状态,但它始终设置为 1,因为 useCallbackpressCount在第一次渲染时将状态记住为 0,每当我们使用 useCallback 中的状态时它始终为 0,所以每次我们按下时,它将是 0+1 = 1。要获取最新值,我们需要将状态添加到 useCallback 内的空数组中。即,useCallback(()=>{...},[pressCount])
所以找到依赖项并填充有点头疼,我知道对吧!?为此,您只需配置 eslint 和 eslint-react-hook,之后 VS 代码将处理它。
在应用之前useCallback
在应用 useCallback 之前
注意激活选项卡的滞后。
应用后useCallback
应用 useCallback 后

3.memo对于整个组件🚦。

用于export default React.memo(AwesomeChild)导出几乎所有的组件,这与 React Class Turf 中的 PureComponent 非常相似。它通过比较上一个和下一个 props 来防止组件的重新渲染,有时它会允许渲染一些不需要的 props 更改,为了提高限制,我们可以使用 areEqual 函数作为React.memo函数的第二个参数,

例子

非限制性备忘录

const AwesomeChild =({text,style})=>{
return(
<Text style={style} >{text}</Text>
)
}
export default React.memo(AwesomeChild)
const AwesomeChild =({text,style})=>{
return(
<Text style={style} >{text}</Text>
)
}
export default React.memo(AwesomeChild)

限制性备忘录
const AwesomeChild =({text,style})=>{
return(
<Text style={style} >{text}</Text>
)
}
const areEqual=(prevProps,nextProps)=>{
// return false prevProps.text & nextProps.text are not equal.
return prevProps.text===nextProps.text
// else all are equal, no re-render
return true
}
export default React.memo(AwesomeChild,areEqual)
const AwesomeChild =({text,style})=>{
return(
<Text style={style} >{text}</Text>
)
}
const areEqual=(prevProps,nextProps)=>{
// return false prevProps.text & nextProps.text are not equal.
return prevProps.text===nextProps.text
// else all are equal, no re-render
return true
}
export default React.memo(AwesomeChild,areEqual)

在此,仅当父组件的 prop 发生变化时,组件才会重新渲染,如果prop 发生变化, text则不会重新渲染。 (在大多数情况下,正常的备忘录可以正常工作) style

4.其他提示🔧。

希望这篇文章能对大家有所帮助。我花了好几个小时才找到答案,希望能分享给大家,毕竟在网上不容易找到。
欢迎留言分享你的想法和技巧……

鏂囩珷鏉ユ簮锛�https://dev.to/ltsharma/performance-optimization-react-native-with-hooks-a77
PREV
Elm 2021 年度回顾 2021 年 1 月 2021 年 2 月 2021 年 3 月 2021 年 4 月 2021 年 5 月 2021 年 6 月 2021 年 7 月 2021 年 8 月 2021 年 9 月 2021 年 10 月 2021 年 11 月 2021 年 12 月
NEXT
用函数式编程治愈冒名顶替综合症