React Native使用Reducer更新屏幕:任务加图后FlatList不实时刷新
问题根因
这类Redux状态已更新但FlatList不刷新的场景,核心触发点一般两个:
- FlatList的虚拟化渲染内置了浅引用判断优化,大部分情况是漏给FlatList绑定
extraData属性。FlatList默认只会追踪dataprop的引用变化触发重渲染,当状态变更没有触达它的内部更新逻辑时,它会一直渲染之前缓存的旧列表内容,只有退出应用重新挂载页面时,才会拉取最新的store值完成渲染。 - 列表渲染链路存在浅对比漏判。哪怕Redux状态已经完成更新,如果列表的key提取规则、列表项组件的props对比逻辑存在缺陷,也会导致需要更新的列表项不重绘,表现和状态没生效完全一致。
对应解决方法
- 给FlatList补上状态追踪配置
渲染列表时必须把从Redux拿到的tasks状态作为extraData属性传入,让列表能实时感知关联状态的变化主动触发重渲染,参考写法:<FlatList data={this.props.tasks} extraData={this.props.tasks} // 必须绑定,否则无法感知状态更新 keyExtractor={(item) => item.taskId.toString()} // 用任务唯一id做key,禁止用数组下标、重复的任务名称做key renderItem={({ item }) => <TaskItem task={item} />} /> - 校验不可变更新逻辑的正确性
你现有reducer的更新逻辑整体符合不可变更新的要求,需要排查两个细节问题:- 确认没有直接篡改旧状态对象,比如不要写
task.image = xxx之后返回旧task实例,否则哪怕重新生成了任务数组,数组内的对象引用没有变化,浅对比会直接判定无更新。你现在写的{...task, image: action.payload.uri}是符合规范的不可变写法。 - 对齐字段映射关系:你dispatch时传递的payload是带
uri字段的任务对象,reducer里把uri值存到了新task的image属性上,要确认列表项渲染图片时读取的是item.image字段,不要和item.uri混淆,否则哪怕状态更新了,渲染层拿不到对应值也会表现为没生效。
- 确认没有直接篡改旧状态对象,比如不要写
- 排查列表项组件的性能优化逻辑
如果列表项用React.memo做了性能优化,要确认自定义的props对比函数没有漏掉image字段的判断。如果对比逻辑只校验了任务标题、完成状态这类字段,漏了图片地址的变化,就会导致图片更新了但是对应项不重绘,参考修正后的对比写法:// 修正:补全image字段的对比判断 export default React.memo(TaskItem, (prevProps, nextProps) => { return ( prevProps.task.title === nextProps.task.title && prevProps.task.isDone === nextProps.task.isDone && prevProps.task.image === nextProps.task.image ) }) - 排查组件内部的状态缓存问题
不要把从Redux props拿到的tasks数据拷贝到组件内部的state里当FlatList的数据源,比如不要在componentDidMount里写this.setState({list: this.props.tasks})之后就一直用state里的list渲染。这种写法下Redux状态更新后props虽然变了,但组件内部缓存的旧数据会一直作为列表数据源,只有重新挂载页面时才会完成更新。
内容的提问来源于stack exchange,提问作者user123456
相关产品推荐
相关产品推荐

