开发中难免会遇到子传父的场景,比如子组件通知父组件状态改变,或者让父组件执行一段逻辑。又或者是父组件要调用子组件中的某些方法,或者获取某些值。
方法一 callback
父组件向子组件传递一个方法(props中),子组件在适当的时机调用该方法
代码实践
父组件代码
const App = () => {
const [ count, setCount ] = useState(0);
const childrenRef = useRef();
const onClick = (val) => {
setCount(val);
}
return <>
<ChildrenComponent onClick={onClick} count={count}/>
</>
}
子组件代码
const ChildrenComponent = ({ onClick, count }) => {
const onBtnClick = () => {
onClick(count+1)
}
return <>
<button onClick={onBtnClick}>
基础子传父组件-通过callback
子组件点击!
</button>
{count}
</>
}
在子组件中触发点击事件,调用父组件传递过来的onClick方法,成功让父组件拿到更新后的count。 这样的子组件也是基础的ui组件。
效果
方法二 ref
父组件通过ref拿到子组件的方法。class组件可以直接拿到子组件的实例,函数组件则需要使用hooks->useImperativeHandle
来转发ref。
btw: 函数组件本身没有ref,如果父组件传参直接使用
<ChildrenComponent ref={ref} />
这样的方式,函数子组件还需要在外层包裹一层forwardRef来实现ref的接收。
class的方式很简单,所以不贴代码了。
FunctionComponent Ref代码实践
父组件代码
const App = () => {
const childrenRef = useRef();
const onFatnerClick = () => {
const {setCountChildren, countChildren} = childrenRef.current || {};
setCountChildren?.(countChildren + 1);
}
return <>
<button onClick={onFatnerClick}>点击父组件,修改ref子组件的count</button>
<RefChildrenComponent ref={childrenRef}/>
</>
}
子组件代码
const RefChildrenComponent = forwardRef((props, ref) => {
const [ countChildren, setCountChildren ] = useState(0);
useImperativeHandle(ref,() => {
return {
setCountChildren,
countChildren
}
},[countChildren])
return <>
ref的子组件{countChildren}
</>
})
子组件通过useImperativeHandle
向父组件传递了setCountChildren
和countChildren
,父组件触发自己的点击事件后,调用了子组件的setCountChildren
方法,改变了子组件的countChildren
。从而使页面更新。