React Hooks 父组件获取子组件的方法
以下讨论父子组件都为函数组件。
只有父子两个层级
1、 父组件创建一个ref作为一个属性传入子组件。子组件根据内部方法的变化动态更改ref(useEffect)
const loopFn = () => {};
function Child(props) {
const { innerRef } = props;
const innerFn = useCallback(() => {
console.error('inner function...');
}, deps);
useEffect(() => {
innerRef.current.innerFn = innerFn;
}, [innerFn]);
}
function Parent(props) {
const ref = useRef({});
const onClick = useCallback(() => {
ref.current.innerFn && ref.current.innerFn()
}, [])
return [
<Child innerRef={ref} />,
<button onClick={onClick}>call inner function</button>
];
}
这种写法到是可以实现,但是感觉不够优雅。尤其是自定义一个属性传入ref。
而且还有引用值清除的问题:
如果此时 Child
组件被更换成 Child1
组件,此时可能 Child1
组件上并没有对此进行处理,则点击按钮就会调用 Child
的 innerFn
方法。
useEffect(() => {
const preInnerFn = innerRef.current.innerFn
innerRef.current.innerFn = innerFn;
return () => {
innerRef.current.innerFn = preInnerFn
}
}, [innerFn]);
2、 父组件获取函数子组件的方法,通过useImplerative
useImplerative
在销毁的时候会将 current
置为 null
。当然在设置值的时候也进行 null
值的容错。
const loopFn = () => {};
function Child(props, ref) {
const { innerRef } = props;
const innerFn = useCallback(() => {
console.error('inner function...');
}, deps);
useImperativeHandle(ref, () => ({
innerFn,
}), [innerFn]);
}
Child = forwardRef(Child)
function Parent(props) {
const ref = useRef({});
const onClick = useCallback(() => {
ref.current.innerFn && ref.current.innerFn()
}, [])
return [
<Child ref={ref} />,
<button onClick={onClick}>call inner function</button>
];
}
第二种方式使用了forwardRef
, useImperativeHandle
,看起来比较符合我们的优雅要求,理解上也比较好理解容易。
多个层级
有 A B C三个组件, A 为父组件,C为最下级
此时有个要求, A获取C的内部方法 acFun
,B获取C的内部方法 bcFun
方案一:
A 组件传入一个 ref
为 acRef
流经 B 组件,B 组件也传入一个 bcRef
, 使用 useimperativehandle
去挂上内部方法。
单若 A B为公共组件的话,就存在一个命名上的约定。 而且A组件获取C组件的内部方法就需要一级级通过props传入
const loopFn = () => {};
function C(props) {
const { acRef, bcRef } = props
const acFun = useCallback(() => {
console.error('acFun... ')
}, deps)
const bcFun = useCallback(() => {
console.error('bcFun... ')
}, deps)
useImperativeHandle(acRef, () => ({
acFun,
}), [acFun])
useImperativeHandle(bcFun, () => ({
bcFun,
}), [bcFun])
}
function B(props) {
const bcRef = useRef({})
const onClick = useCallback(() => {
bcRef.current.bcFun && bcRef.current.bcFun()
}, [])
return [
<C acRef={props.acRef} bcRef={bcRef} />,
<button onClick={onClick}>call inner fun</button>
]
}
function A(props) {
const acRef = useRef({})
const onClick = useCallback(() => {
acRef.current.acFun && acRef.current.acFun()
}, [])
return [
<B acRef={acRef} />,
<button onClick={onClick}>call inner fun</button>
]
}
考虑到在实际过程中 A B, B C, 之间可能不止一级嵌套。
方案二:
针对于层层传递ref的问题 可不可以使用 createContext
尼?看一下createContext
用法
const RefContext = React.createContext({})
function A() {
const ref = useRef({})
return (
<RefContext.Provider value={ref}>
<B />
</RefContext.Provider>
);
}
function C() {
const acRef = React.useContext(RefContext)
useImperativeHandle(acRef, () => {
....//
})
}
但考虑到 ref
是一个引用值且 A 组件会有多个实例,所以这个方案不大可行。
问题/讨论
说出你对多个层级获取下级组件的看法/方案,或者对上述几种方案的看法。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论