React中更新父组件state且不触发子组件重渲染的问题求解
问题解决办法
核心问题根因
- useCallback存在闭包陷阱:你给
useCallback配置的依赖数组为空,导致addArtistPopUp函数永远捕获初始化时的artistPopUps空数组,每次调用setArtistPopUps都是基于初始空数组拼接数据,所以表现为state无法正常更新。 - Graph组件强制重绘:子组件内的
Graph绑定了key={uniqueId()},每次组件渲染都会生成新的唯一key,React会直接销毁旧组件重新创建新实例,必然触发重绘。 - map回调缺少返回值:父组件中
artistPopUps.map的回调函数用了大括号包裹但没有return语句,会导致弹窗组件无法正常渲染。
修正代码
父组件修正
function ArtistGraphContainer() { const [artistPopUps, setArtistPopUps] = useState([]) // 改用setState函数式更新,不需要依赖artistPopUps,保证函数引用永远不变 const addArtistPopUp = useCallback( (artistGeniusId, xPos, yPos) => { setArtistPopUps(prev => [...prev, {artistGeniusId, xPos, yPos}]) }, [], ) return ( <div className='artist-graph-container'> <ArtistGraph addArtistPopUp={addArtistPopUp}></ArtistGraph> {/* 修正map的返回值,同时给弹窗加唯一key */} {artistPopUps.map((popUp, index) => ( <ArtistPopUp key={`${popUp.artistGeniusId}_${index}`} artistGeniusId={popUp.artistGeniusId} xPos={popUp.xPos} yPos={popUp.yPos} ></ArtistPopUp> ))} </div> ) }
子组件修正
function ArtistGraph({addArtistPopUp}) { // querying data if(records) { // wrangling data const events = { doubleClick: function(event) { handleNodeClick(event) } } return ( <div className='artist-graph'> {/* 去掉动态uniqueId,改用固定key或基于不变的graph数据生成的key */} <Graph graph={graph} options={options} events={events} key="fixed-graph-key" > </Graph> </div> ) } else { return(<CircularProgress></CircularProgress>) } } // 可选优化:把默认返回true的比较逻辑改为明确比较props引用,避免后续加新props时出问题 function areEqual(prevProps, nextProps) { return prevProps.addArtistPopUp === nextProps.addArtistPopUp } export default React.memo(ArtistGraph, areEqual)
效果说明
修正后addArtistPopUp的引用永远不会变化,React.memo会判定子组件props无变化跳过重渲染,同时Graph组件的key固定不会被强制重建,既可以正常更新父组件的弹窗state,也不会触发Graph的重绘。
内容的提问来源于stack exchange,提问作者NoobD0gg
相关产品推荐
相关产品推荐

