React JS中如何定向触发指定子组件重渲染且不影响其他同级组件
实现方案
核心逻辑原理
要实现指定组件间的状态同步、同时屏蔽其他非目标组件的重渲染,核心用到两个React原生特性,不需要引入额外状态管理库:
- 父组件更新
state时会触发自身重渲染,配合React.memo的渲染拦截能力,只要非目标组件的props引用没有变化,就会直接跳过渲染流程 - 组件间的状态传递通过props回调链路实现,不需要依赖全局页面刷新
- 仅将目标组件依赖的状态存在父组件的state中,从根源上减少无关组件的感知范围
分步代码改造
1. 改造父组件
父组件仅将需要同步给SecondComponent的搜索值存入state,同时暴露变更回调给FirstComponent,所有非目标组件用React.memo包裹做渲染拦截:
class Parent extends React.Component { constructor() { super(); this.state = { searchValues: { tab1: localStorage.getItem("tab1") || "", tab2: localStorage.getItem("tab2") || "" } } // 绑定回调方法的this指向,避免render时每次生成新的函数引用 this.handleSearchChange = this.handleSearchChange.bind(this) } // 接收FirstComponent传来的变更值,同步更新状态和本地存储 handleSearchChange(name, value) { localStorage.setItem(name, value) this.setState(prev => ({ searchValues: { ...prev.searchValues, [name]: value } })) } render() { // 定义被memo包裹的非目标组件,跳过不必要的重渲 const MemoizedAnotherComponent = React.memo(AnotherComponent) return ( <> {/* 目标组件:仅接收需要渲染的搜索值作为props */} <SecondComponent searchValues={this.state.searchValues} /> {/* 触发变更的组件:接收状态更新回调 */} <FirstComponent onSearchChange={this.handleSearchChange} /> {/* 非目标组件:使用memo包裹,props无变化时不触发渲染 */} <MemoizedAnotherComponent /> <MemoizedAnotherComponent /> <MemoizedAnotherComponent /> </> ); } } export default Parent;
2. 改造FirstComponent
去掉仅操作localStorage的孤立逻辑,在输入变更时调用父组件传入的回调,将值向上传递:
import React from "react"; const FirstComponent = ({ onSearchChange }) => { const handleChange = (event) => { const { name, value } = event.target // 触发父组件状态更新 onSearchChange(name, value) } return ( <div className="container-fluid"> <div className="row"> <div className="col-11 col-md-10 mx-auto"> <h1>All Searches</h1> <input type='text' name='tab1' onChange={handleChange} /> <input type='text' name='tab2' onChange={handleChange} /> </div> </div> </div> ); } export default FirstComponent;
3. 改造SecondComponent
去掉组件内部从localStorage读值初始化state的逻辑,直接消费父组件传入的props渲染内容,保证和FirstComponent的输入实时同步:
import React from 'react'; import { NavLink } from 'react-router-dom' class SecondComponent extends React.Component { render() { const { searchValues } = this.props return ( <div className="d-inline-flex" style={{ background: "#242F84", width: "100%" }}> <NavLink to="/" className="Home"> <p className="mb-0 FS_28 px-2 White">Home</p> </NavLink> <NavLink to="/AllSearches"> <p className="mb-0 White">All Searches</p> </NavLink> <NavLink to="/AllSearches"> <p className="mb-0 White">{searchValues.tab1}</p> </NavLink> <NavLink to="/AllSearches"> <p className="mb-0 White">{searchValues.tab2}</p> </NavLink> </div> ); } } export default SecondComponent;
注意事项
React.memo的拦截逻辑基于props的浅比较,给非目标组件传props时要保证引用稳定,不要在render方法内每次新建对象、新建临时函数传入,否则会导致memo失效- 不需要依赖
window.location.reload实现状态同步,所有值的传递都走React组件的props链路,不会出现全页面刷新导致的状态丢失问题 - 原来的localStorage存储逻辑可以保留,作为页面首次加载时的初始值来源
内容的提问来源于stack exchange,提问作者Abdul Wahab
相关产品推荐
相关产品推荐

