基于useImperativeHandle的使用解析

 更新时间:2022年08月08日 09:30:37   作者:前端精髓  
这篇文章主要介绍了基于useImperativeHandle的使用解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

useImperativeHandle的使用

你不能在函数组件上使用 ref 属性,因为它们没有实例:

import React, { Component } from 'react';
function MyFunctionComponent() {
  return <input />
}
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  render() {
    return (
      <MyFunctionComponent ref={this.textInput} />
    );
  }
}

如果你需要使用 ref,你应该将组件转化为一个 class,就像当你需要使用生命周期钩子或 state 时一样。

不管怎样,你可以在函数组件内部使用 ref 属性,只要它指向一个 DOM 元素或 class 组件:

function CustomTextInput(props) {
  // 这里必须声明 textInput,这样 ref 才可以引用它
  let textInput = React.createRef();
  function handleClick() {
    textInput.current.focus();
  }
  return (
    <div>
      <input
        type="text"
        ref={textInput} />
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );
}

在下面的示例中,MyFunctionComponent 使用 React.forwardRef 来获取传递给它的 ref,然后转发到它渲染的 DOM button:

const MyFunctionComponent = React.forwardRef((props, ref) => (
  <button ref={ref}>
    {props.children}
  </button>
))
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  componentDidMount() {
    console.log(this.textInput.current)
  }
  render() {
    return (
      <MyFunctionComponent ref={this.textInput} />
    );
  }
}

第二个参数 ref 只在使用 React.forwardRef 定义组件时存在。常规函数和 class 组件不接收 ref 参数,且 props 中也不存在 ref。

useImperativeHandle

useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。useImperativeHandle 应当与 forwardRef 一起使用: 

const MyFunctionComponent = React.forwardRef((props, ref) => {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return (
    <input ref={inputRef} />
  )
})
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  componentDidMount() {
    this.textInput.current.focus()
  }
  render() {
    return (
      <MyFunctionComponent ref={this.textInput} />
    );
  }
}

使用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
})

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。 

相关文章

  • React配置Redux并结合本地存储设置token方式

    React配置Redux并结合本地存储设置token方式

    这篇文章主要介绍了React配置Redux并结合本地存储设置token方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • React中的页面跳转方式示例详解

    React中的页面跳转方式示例详解

    React Router提供了几种不同的跳转方式,包括使用组件进行页面跳转、使用组件进行重定向,以及使用编程式导航进行跳转,这篇文章主要介绍了React中的页面跳转方式详解,需要的朋友可以参考下
    2023-09-09
  • React diff算法原理详细分析

    React diff算法原理详细分析

    经典的diff算法中,将一棵树转为另一棵树的最低时间复杂度为 O(n^3),其中n为树种节点的个数。假如采用这种diff算法,一个应用有1000个节点的情况下,需要比较十亿次才能将dom树更新完成,显然这个性能是无法让人接受的
    2022-11-11
  • react.js使用webpack搭配环境的入门教程

    react.js使用webpack搭配环境的入门教程

    本文主要介绍了react 使用webpack搭配环境的入门教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-08-08
  • 详解如何在React组件“外”使用父组件的Props

    详解如何在React组件“外”使用父组件的Props

    这篇文章主要介绍了详解如何在React组件“外”使用父组件的Props,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • 详解React Native与IOS端之间的交互

    详解React Native与IOS端之间的交互

    React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,支持iOS和安卓两大平台。本文将介绍React Native与IOS端之间的交互。
    2021-06-06
  • 详细谈谈React中setState是一个宏任务还是微任务

    详细谈谈React中setState是一个宏任务还是微任务

    学过react的人都知道,setState在react里是一个很重要的方法,使用它可以更新我们数据的状态,下面这篇文章主要给大家介绍了关于React中setState是一个宏任务还是微任务的相关资料,需要的朋友可以参考下
    2021-09-09
  • React实现随机颜色选择器的示例代码

    React实现随机颜色选择器的示例代码

    颜色选择器是一个用于选择和调整颜色的工具,它可以让用户选择他们喜欢的颜色,本文主要介绍了React实现随机颜色选择器的示例代码,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • 深入理解React中何时使用箭头函数

    深入理解React中何时使用箭头函数

    对于刚学前端的大家来说,对于React中的事件监听写法有所疑问很正常,特别是React中箭头函数使用这块,下面这篇文章主要给大家深入的讲解了关于React中何时使用箭头函数的相关资料,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2017-08-08
  • 深入理解react-router 路由的实现原理

    深入理解react-router 路由的实现原理

    这篇文章主要介绍了深入理解react-router 路由的实现原理,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09

最新评论