React forwardRef的使用方法及注意点


Posted in Javascript onJune 13, 2021

之前使用react.forwardRef始终无法应用于react高阶组件中,最近终于捣鼓出来了,于是记录下来。关键点就是React.forwardRef的API中ref必须指向dom元素而不是React组件。

React.forwardRef使用示例

下面就是应用到React组件的错误示例:

const A=React.forwardRef((props,ref)=><B {...props} ref={ref}/>)

这就是我之前经常犯的错误, 这里的ref是无法生效的。

前面提到ref必须指向dom元素,那么正确方法就应用而生:

const  A=React.forwardRef((props,ref)=>(
<div ref={ref}>
<B {...props} />
</div>
))

作用与注意点

  1. 父组件创建一个ref对象,绑定给子组件中的Dom元素或class组件
  2. 函数组件是没有实例的
  3. 高阶组件需做特殊处理

父组件获取子组件中Dom元素实例

React forwardRef的使用方法及注意点

import React, { useRef } from 'react';
import Content from './content';

const Home = () => {
  // 创建一个Ref对象
  const connectRef = useRef(null);

  const handleFoucus = () => {
    const _ref = connectRef.current;
    _ref.focus();
  };

  return (
    <div>
        <button onClick={() => handleFoucus()}>
          使用子组件中DOM元素的方法
        </button>

        <Content ref={connectRef} />
    </div>
  );
};

export default Home;
import React, { forwardRef } from 'react';

/**
 * forwardRef包裹后,ref会作为第二个参数,接收传进来的ref属性
 * e.g.
 * <Content count={count} user={user} ref={connectRef}>
 *
 * @param props - {count, user}
 * @param ref   - connectRef
 * */
const Content = (props, ref) => {
  return (
    <div>
   	  {/* 把ref绑定给传进来的ref ≈ ref={connectRef} */}
      <input type="password" ref={ref} />
    </div>
  )
};

export default forwardRef(Content);

父组件获取子组件中class组件实例

React forwardRef的使用方法及注意点

import React, { useRef } from 'react';
import Content from './content';

const Home = () => {
  // 创建一个Ref对象
  const connectRef = useRef(null);

  const handleAdd = () => {
    const _ref = connectRef.current;

    const { count } = _ref.state;
    _ref.setState({
      count: count + 1
    })
  };

  return (
    <div>
        <button onClick={() => handleAdd()}>
          使用子组件中class组件的属性和方法
        </button>

        <Content ref={connectRef} />
    </div>
  );
};

export default Home;
import React, { forwardRef } from 'react';
import Header from './header';
import Footer from './footer';

/**
 * forwardRef包裹后,ref会作为第二个参数,接收传进来的ref属性
 * e.g.
 * <Content count={count} user={user} ref={connectRef}>
 *
 * @param props - {count, user}
 * @param ref   - connectRef
 * */
const Content = (props, ref) => {
  return (
    <div>
      {/* 把ref绑定给传进来的ref ≈ ref={connectRef} */}
      <Header ref={ref} />  {/* class组件 */}
		
      {/* <Footer ref={ref} /> 函数组件是没有实例的,所以connectRef.current: null */}
    </div>
  )
};

export default forwardRef(Content)
import React from 'react';

export default class Header extends React.Component {
  state = {
    count: 0
  };

  render() {
    return (
      <div>
        {this.state.count}
      </div>
    )
  }
};

高阶组件中的特殊情况

高阶组件会把所有接收到的props,传递给被包装的组件(透传)
ref 和 key 类似,不是一个prop,所以不会透传,ref会绑定到外层的包装容器上

/*
  处理ref
  e.g. Hoc1(Hoc2(Content))

  <Content ref={myRef} /> 给Content绑定的ref会绑定到Hoc1上,且不会继续向下传递

  第一种方法 React.forwardRef ===============

      在 Hoc1外面 用React.forwardRef()对ref做处理,用props来传递ref
      0. 在高阶组件外面包裹forwardRef,拦截获取ref,增加一个props(xxx={ref}),真实组件通过props.xxx获取
      1. 使用时传 ref={XXXX}  // 和第二种方法不同的地方
      2. 用forwardRef的第二个参数获取 ref
      3. 增加一个新的props,用来向下转发ref  e.g. forwardedRef={ref}
      4. 真实组件中绑定 ref={props.forwardedRef}

      const Home = (props) => {
        const connectRef = useRef(null);

        return (
          <div>
            <Content ref={connectRef} />
          </div>
        );
      };

      // 被包装组件
      const Content = (props) => {
        return (
          <div>
            <input type="password" ref={props.forwardedRef} />
          </div>
        );
      };


      // forwardRef的第二个入参可以接收ref,在Hoc外层对ref做处理
      export default React.forwardRef((props, ref) => {
        const Wrapper = React.memo(Content);  // Hoc

        // forwardRef包裹的是Wrapper
        // 需要在Wrapper中把ref向下传递给真实组件
        // Wrapper中增加一个props属性,把ref对象作为props传给子组件
        return <Wrapper {...props} forwardedRef={ref} />;
      });

  第二种方法 ==========

  0. 使用时就用一个props来保存ref
  1. 使用时传 xxx={ref}  // 和第一种方法的不同点
  2. 真实组件中绑定 ref={props.xxx}

  const Home = (props) => {
    const connectRef = useRef(null);

    return (
      <div>
        <Content forwardedRef={connectRef} />
      </div>
    );
  };

  // 定义高阶组件
  export const Hoc = (WrappedComponent) => {
    class Wrapper extends React.Component {
      render() {
        return <WrappedComponent {...props} />
      }
    }
  }

  // 被包装的组件
  const Content = (props) => {
    return (
      <div>
        <input type="password" ref={props.forwardedRef} />
      </div>
    );
  };

  // 包装过程
  export default Hoc(Content);

* */

以上就是React forwardRef的使用方法及注意点的详细内容,更多关于React forwardRef使用的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
jQuery.Validate 使用笔记(jQuery Validation范例 )
Jun 25 Javascript
js中查找最近的共有祖先元素的实现代码
Dec 30 Javascript
jQuery.clean使用方法及思路分析
Jan 07 Javascript
php is_numberic函数造成的SQL注入漏洞
Mar 10 Javascript
jquery实现手机号码选号的方法
Jul 31 Javascript
AngularJS中的包含详细介绍及实现示例
Jul 28 Javascript
Angular实现点击按钮后在上方显示输入内容的方法
Dec 27 Javascript
微信小程序实现YDUI的ScrollTab组件
Feb 02 Javascript
vue实现提示保存后退出的方法
Mar 15 Javascript
微信小程序wepy框架学习和使用心得详解
May 24 Javascript
基于Vue实现平滑过渡的拖拽排序功能
Jun 12 Javascript
vue+axios实现post文件下载
Sep 25 Javascript
原生Javascript+HTML5一步步实现拖拽排序
JS代码编译器Monaco使用方法
React中的Context应用场景分析
Jun 11 #Javascript
详解JVM系列之内存模型
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
一文搞懂redux在react中的初步用法
Jun 09 #Javascript
深入详解JS函数的柯里化
Jun 09 #Javascript
You might like
用PHP和ACCESS写聊天室(十)
2006/10/09 PHP
利用static实现表格的颜色隔行显示
2006/10/09 PHP
php使用sql数据库 获取字段问题介绍
2013/08/12 PHP
php中json_encode处理gbk与gb2312中文乱码问题的解决方法
2014/07/10 PHP
php导入大量数据到mysql性能优化技巧
2014/12/29 PHP
PHP的Yii框架使用中的一些错误解决方法与建议
2015/08/21 PHP
WordPress中制作导航菜单的PHP核心方法讲解
2015/12/11 PHP
PHP Trait功能与用法实例分析
2020/06/03 PHP
Ext.FormPanel 提交和 Ext.Ajax.request 异步提交函数的区别
2009/11/12 Javascript
深入理解Javascript中this的作用域
2014/08/12 Javascript
js生成的验证码的实现与技术分析
2014/09/17 Javascript
javascript动态修改Li节点值的方法
2015/01/20 Javascript
jQuery判断元素是否显示 是否隐藏的简单实现代码
2016/05/19 Javascript
jquery.validate使用详解
2016/06/02 Javascript
Vuex之理解Getters的用法实例
2017/04/19 Javascript
vue添加class样式实例讲解
2019/02/12 Javascript
jquery实现自定义树形表格的方法【自定义树形结构table】
2019/07/12 jQuery
element-ui中按需引入的实现
2019/12/25 Javascript
OpenLayers3实现测量功能
2020/09/25 Javascript
Python3通过Luhn算法快速验证信用卡卡号的方法
2015/05/14 Python
python绘制无向图度分布曲线示例
2019/11/22 Python
Pycharm 2020最新永久激活码(附最新激活码和插件)
2020/09/17 Python
手动安装python3.6的操作过程详解
2020/01/13 Python
python GUI库图形界面开发之PyQt5 Qt Designer工具(Qt设计师)详细使用方法及Designer ui文件转py文件方法
2020/02/26 Python
python输出数学符号实例
2020/05/11 Python
使paramiko库执行命令时在给定的时间强制退出功能的实现
2021/03/03 Python
详解CSS3 用border写 空心三角箭头 (两种写法)
2017/09/29 HTML / CSS
谈一谈HTML5本地存储技术
2016/03/02 HTML / CSS
Sperry官网:帆船鞋创始品牌
2016/09/07 全球购物
英国森林假期:Forest Holidays
2021/01/01 全球购物
什么是跨站脚本攻击
2014/12/11 面试题
人事主管岗位职责
2014/01/30 职场文书
《蒲公英》教学反思
2014/02/28 职场文书
技术总监管理岗位职责
2014/03/09 职场文书
2019企业文化管理制度范本!
2019/08/06 职场文书
关于MySQL中explain工具的使用
2023/05/08 MySQL