useEffect更新父组件状态后子组件props状态读取异常排查
异常原因
这是React useState钩子的标准运行机制导致的,不属于框架bug:
useState接收的初始值参数仅在组件首次挂载的第一次渲染时生效,后续组件因props变更、父组件重渲染触发更新时,React会直接保留该state已存储的值,完全忽略传入的初始参数,不会自动将props的更新同步到组件本地state中。- Second组件没有维护独立的本地状态,每次渲染都直接读取当前最新的props值,因此父组件通过
setSomeVar更新状态后,Second能立刻拿到新的数组['a','b','c']完成渲染。 - First组件首次挂载时,用当时props携带的初始值
['a']完成了本地stateletters的初始化,后续父组件props更新触发First重渲染时,useState(props.letters.dos)这行代码不会再把新传入的props值写入本地state,组件始终读取首次初始化的本地state值,因此只渲染初始的a,看不到后续追加的b、c。
相关代码
App.js
import './App.css'; import First from './First'; import Second from './Second'; import { useEffect, useState } from 'react'; function App() { const [someVar, setSomeVar] = useState({dos:['a']}); useEffect(()=>{ console.log('useEffect') setSomeVar({dos:['a', 'b', 'c']}) }, []) return ( <div className="App"> <header className="App-header"> <First letters={someVar}></First> <hr/> <Second letters={someVar}></Second> </header> </div> ); } export default App;
First.js
import { useState } from "react"; export default function First(props) { const [letters, setLetter] = useState(props.letters.dos); return ( <div> {letters.map((letter) => { return <span key={letter}>{letter}</span>; })} </div> ); }
Second.js
export default function Second(props) { return ( <div> {props.letters.dos.map((letter) => { return <span key={letter}>{letter}</span>; })} </div> ); }
渲染效果

内容的提问来源于stack exchange,提问作者mjsr
相关产品推荐
相关产品推荐

