您的位置:首页技术文章

解决react-connect中使用forwardRef遇到的问题

【字号: 日期:2023-06-25 15:07:58浏览:11作者:馨心
目录
  • react-connect使用forwardRef遇到的问题
    • 项目场景
    • 原因
    • 问题描述
    • 解决方案
  • React.forwardRef的使用说明
    • 应用场景
    • 但问题来了
  • 总结

    react-connect使用forwardRef遇到的问题

    项目场景

    之前独立的两个tab, tab1和tab2, 由于需求变更, 要把这两个tab都放到一个tab4下, 变化大概是从图1变为图2

    原因

    子组件用了使用了connect, 相当于把forwardRef隔离了,导致父组件拿不到想要的方法, 所以需要把forwardRef 透传给使用了connect 的子组件

    问题描述

    tip: 该文章以下内容中说的子组件指tab1和tab2, 父组件指tab4

    tab1和tab2组件都有"更新数据"按钮,将他们合并为tab4里面之后,"更新数据"按钮已经变成了父组件(tab4)的内容, 但是由于按钮的onClick事件中的逻辑太复杂, 所以点击事件没有挪出来重新写到父组件里。

    也就是:按钮在父组件中, 按钮的点击事件在子组件里写。

    子组件和父组件都是用函数组件 + Hook 写的, 并且子组件中都用了connect, 此时父组件想调用子组件的点击事件方法, 该怎么拿到子组件里的方法呢?

    解决方案

    tip: 我的项目使用的是umi2

    利用Hoc(高阶组件)透传ref

    import React, { forwardRef, useImperativeHandle, useState, useEffect } from 'react';
    import { connect } from 'dva'
    const Children = (props) => {
      const { refInstance } = props
      const [text, setText] = useState('子组件:Children')
      const functionA = () => {
        console.log('c2方法')
        setText('ref改变了')
      }
      useImperativeHandle(refInstance, () => ({
        functionA,
        text,
      }))
    return (
        <div>
          {text}
        </div>
    )}
    const newA =  connect((state) => {
      return {
        list: state.list,
      }
    })(Children)
    // 使用Hoc 透传 ref
    export default forwardRef((props, ref) => <newA  {...props} refInstance={ref} />);

    React.forwardRef的使用说明

    forwardRef实际上就是当父组件需要得到子组件元素时,可以利用forwardRef来实现。

    该方法接受一个有额外ref参数的react组件函数,不调用该方法,普通的组件函数是不会获得该参数的。

    应用场景

    ref 的作用是获取实例,可能是 DOM 实例,也可能是 ClassComponent 的实例。

    但问题来了

    如果目标组件是一个 FunctionComponent 的话,是没有实例的(PureComponent),此时用 ref 去传递会报错

    React.forwardRef 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见,但在以下两种场景中特别有用:

    • 转发 refs 到 DOM 组件
    • 在高阶组件中转发 refs

    实例:

    点击搜索按钮时,让文本输入框处于聚焦状态

    1、普通用法:

    import React, { Component } from 'react'
    export default class App extends Component {
      mytext=null
      render() {
        return (
          <div>
            <button type="button" onClick={()=>{
              console.log(this.mytext);
              this.mytext.current.focus()
              this.mytext.current.value="2222"
            }}>获取焦点</button>
            <Child callback={(el)=>{
              console.log(el);、
              //el是临时变量,用全局的去接这个值
              this.mytext=el
              //console.log(el.current);
            }}/>
          </div>
        )
      }
    }
    class Child extends Component {
      mytext = React.createRef();
      //组件渲染完了执行
      componentDidMount() {
        this.props.callback(this.mytext);
      }
      render() {
        return (
          <div style={{background:"yellow"}}>
            <input defaultValue="1111" ref={this.mytext}></input>
          </div>
        );
      }
    }

    2、使用forwardRef

    import React, { Component,forwardRef } from 'react'
    export default class App_forwardRef extends Component {
      mytext=React.createRef()
      render() {
        return (
          <div>
          <button type="button" onClick={()=>{
            console.log(this.mytext);
            this.mytext.current.value="2222"
          }}>获取焦点</button>
          <Child ref={this.mytext}/>
          </div>
        )
      }
    }
    //这里Child是函数式组件
    const Child=forwardRef((props,ref)=>{
        return (
          <div>
            <input defaultValue="11111" ref={ref}></input>
          </div>
        );
    })

    总结

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

    标签: JavaScript