React中如何从Content子组件修改对应父Block组件的状态与属性
实现方案
这里提供两种常用的实现方式,可根据实际业务场景选择:
方案1:Render Props模式(适合Content层级较浅的场景)
将Block的状态维护在自身内部,通过函数形式的content属性把状态修改方法透传给子组件即可,具体实现如下:
改造Block组件
import { useState } from 'react'; function Block(props) { // 内部维护Block自身状态,初始值从传入的props获取 const [title, setTitle] = useState(props.title); const [classes, setClasses] = useState(props.classes); // 封装状态修改方法,避免直接暴露setState给下层 const addClass = (newClass) => { if (!classes.includes(newClass)) { setClasses(prev => [...prev, newClass]); } }; const removeClass = (targetClass) => { setClasses(prev => prev.filter(cls => cls !== targetClass)); }; const blockCtrlMethods = { setTitle, addClass, removeClass }; return ( <div id={props.id} className={classes.join(" ")}> <h2>{title}</h2> {/* 如果content是函数,就把控制方法作为参数传入执行,否则直接渲染 */} {typeof props.content === 'function' ? props.content(blockCtrlMethods) : props.content} </div> ) }
调整App组件传参
function App() { return ( <div> <Block id="users-component" title="Users Table" classes={[]} content={() => <MyTable class="users" />} /> <Block id="status-component" title="Status Component" classes={[]} // 接收Block透传的控制方法,传入Status组件 content={(blockCtrl) => <Status class="status" {...blockCtrl} />} /> <Block id="bdays-component" title="Bdays Component" classes={[]} content={(blockCtrl) => <Bdays class="bdays" {...blockCtrl} />} /> </div> ) }
调整Content组件逻辑
直接调用传入的控制方法即可修改对应Block的状态:
function Status(props) { const handleClick = (title) => { props.setTitle(title) } return ( <div className={props.class}> <button onClick={() => handleClick("newTitle")}>New Title</button> </div> ) } function Bdays(props) { const handleClick = (newClass) => { props.addClass(newClass) } return ( <div className={props.class}> <button onClick={() => handleClick("newClass")}>New Class</button> </div> ) }
方案2:Context模式(适合Content嵌套层级深的场景)
如果Content组件内部还有多层嵌套,逐层传递props过于繁琐,可以用Context实现跨层级传递控制方法:
import { useState, createContext, useContext } from 'react'; // 创建Block专属Context const BlockContext = createContext(); function Block(props) { const [title, setTitle] = useState(props.title); const [classes, setClasses] = useState(props.classes); const addClass = (newClass) => { if (!classes.includes(newClass)) setClasses(prev => [...prev, newClass]); }; const removeClass = (targetClass) => { setClasses(prev => prev.filter(cls => cls !== targetClass)); }; return ( <BlockContext.Provider value={{ setTitle, addClass, removeClass }}> <div id={props.id} className={classes.join(" ")}> <h2>{title}</h2> {/* 不需要再用函数形式传参,直接传入content即可 */} {props.content} </div> </BlockContext.Provider> ) } // 下层组件直接通过useContext获取控制方法,不需要逐层传props function Bdays(props) { const { addClass } = useContext(BlockContext); const handleClick = (newClass) => { addClass(newClass); } return ( <div className={props.class}> <button onClick={() => handleClick("newClass")}>New Class</button> </div> ) }
内容的提问来源于stack exchange,提问作者PoZuTPoH
相关产品推荐
相关产品推荐

