React Native 跳转至子页前列表状态更新异常问题排查
问题根因
你遇到的是典型的React闭包陷阱问题:
useLayoutEffect的依赖数组仅填写了navigation,只会在组件首次渲染时执行一次,给顶部导航栏设置的headerRight按钮绑定的是首次渲染时的handleOpenNewTask函数实例- 这个初始的函数实例闭包捕获的
taskList永远是初始的空数组,后续taskList状态更新后,旧的函数实例不会同步感知到状态变化,因此每次点击新增按钮打印的都是旧值 - 另外你的
onTaskCreated函数也存在闭包问题,后续连续多次新增时也可能出现状态覆盖的情况
解决方案
按以下步骤修改代码即可:
- 用
useCallback包裹回调函数,同时状态更新改用函数式写法,避免依赖外部状态 - 把
handleOpenNewTask加入useLayoutEffect的依赖数组,状态变化后自动更新导航栏按钮的绑定事件
修改后完整代码
// Parent.js import { useCallback } from 'react' // 省略其他代码... // 回调函数用useCallback包裹,状态更新用函数式写法避免依赖taskList const onTaskCreated = useCallback(({ newTask, id }) => { setTaskList(prevTaskList => { // 基于上一次的最新状态更新,不会出现闭包旧值问题 return [...prevTaskList, {value: id}] }); }, [setTaskList]); // 用useCallback包裹,依赖变更时自动生成新的函数实例 const handleOpenNewTask = useCallback(() => { // 这里拿到的永远是最新的taskList console.log(taskList) navigation.navigate(routes.NEW_TASK, { onTaskCreated }); }, [navigation, onTaskCreated, taskList]); // 把用到的外部依赖都加进去 // 新增handleOpenNewTask作为依赖,状态更新后自动重设导航按钮 useLayoutEffect(() => { navigation.setOptions({ headerRight: () => ( <NewTaskHeaderRight onClick={handleOpenNewTask} /> ), }); }, [navigation, handleOpenNewTask]);
额外优化点
如果不需要在handleOpenNewTask里读取taskList,可以把taskList从useCallback的依赖数组中移除,进一步减少不必要的导航栏更新。
内容的提问来源于stack exchange,提问作者denistepp
相关产品推荐
相关产品推荐

