React多同类型Sorting组件仅最后一个DOM更新问题排查求助
问题解决:多个Sorting子组件仅最后一个更新的原因与修复
核心问题原因
你在父组件中使用了**单个React.createRef()**绑定所有子组件,当通过map循环渲染多个<Sorting>时,这个ref会被逐个覆盖,最终只会指向最后一个渲染完成的子组件。所以调用this.child.current.fillArray()时,只有最后一个子组件会执行更新逻辑。
另外还有两个次要问题:
- 子组件没必要把props的array存到自己的state里,完全可以直接使用props值,这样父组件array更新时子组件会自动同步渲染
componentDidMount里的await this.resetTheArray()无效,因为resetTheArray里的setState是异步操作,不会返回Promise,await不会等待它完成
修复方案
方案1:使用数组存储所有子组件的ref(保留子组件fillArray方法)
修改父组件代码,用数组保存每个子组件的ref,调用时遍历所有ref触发更新:
class MainPage extends Component { constructor(props) { super(props); this.state = { array: [], temp: [1, 2, 3] }; // 用数组存储所有子组件的ref this.childRefs = []; } randomNumber(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min) + min); } componentDidMount() { this.resetTheArray(); } resetTheArray() { const temp = []; for (let i = 0; i < 15; i++) { temp.push(this.randomNumber(5, 750)); } this.setState({ array: temp }); } onClickFillArray = () => { // 遍历所有子组件ref,调用fillArray this.childRefs.forEach(child => child.fillArray()); } render() { return ( <div> <NavBar /> {this.state.temp.map((e) => ( <Sorting key={e} // 将每个子组件的ref存入数组 ref={(el) => this.childRefs.push(el)} id={e} array={[...this.state.array]} /> ))} <button onClick={this.onClickFillArray}>click here</button> <button onClick={() => this.onClickBubbleSort()}>Sort me </button> </div> ); } }
方案2:优化子组件,直接依赖props自动更新(更推荐)
子组件不需要自己维护array状态,直接使用props传递的array,这样父组件array更新时,所有子组件会自动重新渲染,省去手动调用fillArray的步骤:
修改子组件代码:
class Sorting extends Component { constructor(props) { super(props); this.state = { bars: NumberOfBars, firstSelection: "Insertion", btn: false, dual: true, }; this.bubbleSort = this.bubbleSort.bind(this); } // 移除fillArray方法,不再将array存入子组件state render() { // 直接使用props中的array const { array } = this.props; return ( <Container> <h1>{`component-${this.props.id}`}</h1> <div className="theContainer"> {array.map((value, idx) => ( <div className={"theBar " + this.props.id} key={idx} style={{ height: `${value}px` }} ></div> ))} </div> <button onClick={this.bubbleSort}>sort</button> {/* reset按钮直接调用父组件的重置方法 */} <button onClick={this.props.onReset}>reset</button> </Container> ); } }
父组件修改,传递onReset方法:
class MainPage extends Component { // ... 其他代码不变 render() { return ( <div> <NavBar /> {this.state.temp.map((e) => ( <Sorting key={e} id={e} array={[...this.state.array]} onReset={() => this.resetTheArray()} /> ))} <button onClick={() => this.resetTheArray()}>click here</button> <button onClick={() => this.onClickBubbleSort()}>Sort me </button> </div> ); } }
额外说明
- 方案2更符合React的数据流设计:父组件维护状态,子组件仅负责渲染和交互,避免了不必要的状态同步问题
- 父组件中
resetTheArray里的this.setState({ array: temp })是异步的,如果需要在数组更新后做某些操作,可以使用setState的回调:
resetTheArray() { const temp = []; for (let i = 0; i < 15; i++) { temp.push(this.randomNumber(5, 750)); } this.setState({ array: temp }, () => { // 数组更新完成后的操作 console.log("array updated:", this.state.array); }); }
内容的提问来源于stack exchange,提问作者mo7a
相关产品推荐
相关产品推荐

