使用useImperativeHandle时父组件第一次没拿到子组件方法

使用useImperativeHandle时父组件第一次没拿到子组件方法

背景需求

一个tab两个按钮A、B,默认选中的A,当点击到B时需要显示B对应的图表。考虑到B的图表在页面加载时已经初始化完成,所以点击B时再调用图表的resize方法。由于tab中的图表是写在子组件里,所以通过useImperativeHandle实现父组件调用子组件方法,React版本"react": "^18.1.0",代码如下

  • 父组件:
const childRef = useRef()
const item = [{
        name: 'XXXX',
        content: <RunningRecord cRef={childRef} />,
        handClick: childRef.current?.resizeChart
}]

return <>
    ……
    <li onClick={() => {
            setTimeout(() => {
                console.log('~~item.handClick',item.handClick)
                item.handClick?.()
            }, 200)
        }}
        key={item.name}>
        {item.name}
    </li>
    ……
    <RunningRecord cRef={childRef} />
</>
  • 子组件:
function RunningRecord({ cRef }) {
    ……
    useImperativeHandle(cRef,()=>({
        resizeChart:()=> {dosomething……}
    }))

问题

这样写在本地开发模式中正常运行,但生产环境中父组件首次加载不能拿到子组件的方法,需tab切换到A再次且到B才行。猜想原因,大概在生产环境中,父组件把子组件暴露出来的方法绑定到UI中的点击事件中,而子组件初始化的时机晚,初始完成后并没有把事件传回来。
这个猜想不一定准确,欢迎知道的小伙伴们补充。

解决方法

在父组件中,将子组件赋值的过程放在useEffect中,不写依赖项参数(不是没有依赖的空数组),再运行,一切正常。

const usageRecordData = [{
    name: 'XXXX',
    content: <RunningRecord cRef={childRef} />,
}]

useEffect(() => {
    usageRecordData[1].handClick = childRef.current?.resizeChart
})
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在React中,父组件可以通过不同的方式获取组件的回调函数。 方法一:通过props传递回调函数 在父组件中定义一个函数,并将该函数作为props传递给组件组件在适当的时机调用该函数,从而实现父组件获取组件的回调。 ```jsx // 父组件 import React, { Component } from 'react'; import Child from './Child'; class Parent extends Component { handleChildEvent = (childInstance) => { // 在父组件中获取组件的实例 console.log(childInstance); // 调用组件方法 childInstance.sendMessage(); } render() { return ( <div> <Child onChildEvent={this.handleChildEvent} /> </div> ); } } export default Parent; ``` ```jsx // 组件 import React, { Component } from 'react'; class Child extends Component { componentDidMount() { // 在组件完成挂载时,将组件的实例作为参数传递给父组件的函数 this.props.onChildEvent(this); } sendMessage = () => { console.log('sending message'); } render() { return ( <span>Child</span> ); } } export default Child; ``` 方法二:使用React.createRef() 在父组件使用React.createRef()创建一个ref对象,并将该ref对象传递给组件组件通过useImperativeHandle将自己的方法暴露给父组件。 ```jsx // 父组件 import React, { useRef } from 'react'; import Child from './Child'; const Parent = () => { const childRef = useRef(null); const handleChildEvent = () => { // 在父组件中调用组件方法 childRef.current.sendMessage(); } return ( <div> <Child onRef={childRef} /> <button onClick={handleChildEvent}>Call Child Method</button> </div> ); } export default Parent; ``` ```jsx // 组件 import React, { useImperativeHandle, forwardRef } from 'react'; const Child = forwardRef((props, ref) => { const sendMessage = () => { console.log('sending message'); } // 将组件方法暴露给父组件 useImperativeHandle(ref, () => ({ sendMessage })); return ( <span>Child</span> ); }); export default Child; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值