React将组件存入state后传入的props未随状态同步更新
问题产生原因
- 代码中存入
articlestate的是已经实例化的不可变JSX元素对象,而非可复用的组件定义。JSX元素本质是React用于描述视图的纯数据快照,在创建完成的瞬间就固定了当时携带的所有props值,不会随外层父组件的state更新自动同步新值。 - 当外层
addArticle状态变化触发父组件重渲染时,React会对state数组里存储的旧JSX对象做diff对比,识别到对象引用没有变化,就会直接沿用之前的渲染结果,不会重新给这些旧元素传入最新的props。这就是为什么只有新追加进数组的JSX元素能读到最新的addArticle值,数组中已存在的旧元素props永远停留在创建时刻的快照值。 - 附带逻辑问题:代码中把axios请求直接写在Article组件的渲染流程里,只要组件触发重渲染就会重复发请求,不符合React的副作用执行规范。
修复方案
核心思路是永远不要把预先生成的JSX元素存入state,state中只存储驱动视图的纯配置数据,组件在渲染阶段根据配置动态生成,确保每次渲染时都能拿到最新的props值。也就是遵循渲染时生成、不预先固化JSX到可变状态的React设计规范。
- 第一步:调整state的存储内容,把原有的“存JSX组件”改成“存对应配置元数据”
原逻辑(直接把JSX塞进state):
调整为存储纯数据配置:setArticle([...article, <Article create="true" post={addArticle} updateError={props.updateError} updateArticle={UpdateArticleCallback}/>])setArticle(prevList => [...prevList, { mode: 'create', // 标记当前条目为新建文章态 id: Date.now() // 生成稳定唯一id替代数组索引做key }]) - 第二步:渲染阶段根据配置动态生成Article组件,传入最新的prop值
原逻辑(直接拿state里存的JSX渲染):
调整为动态生成组件:{article.map((ArticleComp, i) => ( <div className="light-blue p-4 mb-3 mt-3" key={i}> {ArticleComp} <button ... onClick={() => removeArticle(i)}>Delete</button> </div> ))}{article.map((item, i) => ( <div className="light-blue p-4 mb-3 mt-3" key={item.id}> {item.mode === 'create' && ( <Article create="true" post={addArticle} // 每次渲染都会传入最新的addArticle值 updateError={props.updateError} updateArticle={UpdateArticleCallback} /> )} <button type="button" className="red-button ml-2" onClick={() => removeArticle(i)} > Delete </button> </div> ))} - 第三步:调整Article组件的副作用逻辑,把axios请求从渲染流程移到
useEffect中,避免渲染时重复触发请求
原逻辑(在组件顶层直接执行异步请求):
调整为符合React规范的副作用写法:if (props.post !== "no") { axios.post('/api/v1/article/create.php', {...}) }const [title, setTitle] = useState("") const [content, setContent] = useState("") useEffect(() => { // 非编辑/新建态不执行请求 if (props.edit !== "true" && props.create !== "true") return; // post值无效时不执行请求 if (props.post === "no") return; axios.post('/api/v1/article/create.php', { title: title, content: content, job_id: props.post }).then(response => { if(response.data.Message === 'OK'){ props.updateError(null) props.updateArticle() } else { props.updateError(response.data.Error) } }) // 依赖对应的值变化才触发请求 }, [props.post, props.create, props.edit, title, content]);
内容的提问来源于stack exchange,提问作者ewsclass66
相关产品推荐
相关产品推荐

