React触发子组件时错误重渲染其他组件问题排查
React组件state更新时控制台输出异常问题解决
问题场景
项目包含App.jsx和Child.jsx两个组件,操作Child1的输入框触发state更新时,控制台预期输出child1,实际却显示child3。即使给Child组件添加了key属性,问题仍未解决。
相关代码
App.jsx
import React,{useState,useEffect} from 'react'; import {Child} from './Child.jsx' export function App(props) { [message,setMessage]=useState(''); [showChild1,setShowChild1]=useState(true); [showChild2,setShowChild2]=useState(true); [showChild3,setShowChild3]=useState(true); [child1data,setChild1data] = useState('child1'); [child2data,setChild2data] = useState('child2'); [child3data,setChild3data] = useState('child3'); useEffect(() => { console.log('parent was rendered') }) return ( <div className='App'> <button onClick={()=>setShowChild1(!showChild1)}>Show child1</button> {showChild1 && <Child key='1' data={child1data}/>} <br/> <br/> <button onClick={()=>setShowChild2(!showChild2)}>Show child2</button> {showChild2 && <Child key='2'data={child2data}/>} <br/> <br/> <button onClick={()=>setShowChild3(!showChild3)}>Show child3</button> <br/> {showChild3 && <Child key='3' data={child3data}/>} </div> ); } // Log to console console.log('Hello console')
Child.jsx
import React, {useState, useEffect} from 'react'; export const Child = (props) => { const {data} = props; [message,setMessage]=useState(''); useEffect(()=>{ console.log(data) console.log(message) }) return <> <h1>This is {data}</h1> <input onChange={((e)=>setMessage(e.target.value))}></input> </> }
问题原因
- useEffect未设置依赖数组:Child组件的useEffect没有指定依赖,每次组件渲染(自身state更新、父组件重渲染触发的子组件更新)都会执行日志输出。操作Child1输入框时,Child1的state更新触发自身渲染,同时父组件的useEffect也无依赖,会触发父组件重渲染,导致所有当前显示的Child组件都执行useEffect,最后一条日志来自Child3,造成误解。
- 父组件存在冗余state:
[message,setMessage]=useState('');这个state未在组件中使用,却会随父组件渲染存在,增加了不必要的渲染触发可能。
解决方案
1. 给useEffect添加精准依赖数组
修改Child组件的useEffect,仅在data或message变化时执行:
useEffect(()=>{ console.log(data) console.log(message) }, [data, message]) // 添加依赖数组,限定执行时机
修改父组件的useEffect,若仅需在挂载时执行则添加空数组,或根据业务需求添加对应依赖:
useEffect(() => { console.log('parent was rendered') }, []) // 仅组件挂载时执行一次
2. 移除冗余state(可选优化)
删除父组件中未使用的message state:
// 移除该行冗余代码 // [message,setMessage]=useState('');
经过以上修改,操作Child1的输入框时,控制台只会输出Child1对应的child1和输入内容,不会再出现其他Child组件的日志。
内容的提问来源于stack exchange,提问作者Ae Leung
相关产品推荐
相关产品推荐

