React Context传递函数更新状态数组时视图不更新及状态重置问题
问题原因
你遇到的问题由两个典型的React开发错误导致:
- 违反状态不可变原则
你最初的AddOne实现直接修改原数组的引用,linesTmp和原lines是同一个内存地址,React对state做浅比较时认为状态没有变化,因此跳过了组件重渲染,这是首次点击按钮列表不更新的原因。使用setLines([...lines, text])生成新数组的写法解决了这个问题。 - 闭包陷阱
你在Provider组件的空依赖useEffect中仅在组件挂载时向Context注入了一次addOne函数,这个函数捕获的是首次渲染时的lines初始值(空数组)。之后每次调用addOne时,都是基于这个初始空数组计算新状态,所以每次调用都会覆盖之前的更新内容,表现为状态被重置。
修复方案
修改AddOne函数为函数式更新,直接从React内部拿到最新的state值,不需要依赖外部的lines变量,从根源避免闭包问题。如果需要减少Context的更新频率,可以搭配useCallback稳定函数引用。
修复后的Provider组件完整代码:
import React, {useEffect, useState, useCallback} from 'react'; type ProviderProps = { setActions: React.Dispatch<React.SetStateAction<{ addOne?: ((t: string) => void) }>> } const Provider = ({setActions}: ProviderProps) => { const [lines, setLines] = useState<string[]>([]) // 用函数式更新+useCallback,稳定函数引用,避免闭包问题 const AddOne = useCallback((text: string) => { setLines(prevLines => [...prevLines, text]) }, [setLines]) useEffect(() => { setActions({addOne: AddOne}) }, [AddOne, setActions]) return (<> <h1>Lines : </h1> {lines.map((line, index) => ( <p key={index}>{line}</p> ))} </>) } export default Provider;
内容的提问来源于stack exchange,提问作者Kian Soltani
相关产品推荐
相关产品推荐

