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 相关文章推荐
javascript的trim,ltrim,rtrim自定义函数
Sep 21 Javascript
javascript string字符串优化问题
Jul 31 Javascript
深入理解JSON数据源格式
Jan 10 Javascript
js截取中英文字符串、标点符号无乱码示例解读
Apr 17 Javascript
Node.js模块加载详解
Aug 16 Javascript
js判断鼠标左、中、右键哪个被点击的方法
Jan 27 Javascript
javascript实现在网页中运行本地程序的方法
Feb 03 Javascript
Angular ng-repeat遍历渲染完页面后执行其他操作详细介绍
Dec 13 Javascript
Bootstrap CSS组件之按钮下拉菜单
Dec 17 Javascript
js 输入框 正则表达式(菜鸟必看教程)
Feb 19 Javascript
解决Layui 表单提交数据为空的问题
Aug 15 Javascript
详解vue 数组和对象渲染问题
Sep 21 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
phpinfo 系统查看参数函数代码
2009/06/05 PHP
php实现用户在线时间统计详解
2011/10/08 PHP
PHP static局部静态变量和全局静态变量总结
2014/03/02 PHP
PHP模板解析类实例
2015/07/09 PHP
php安全配置记录和常见错误梳理(总结)
2017/03/28 PHP
Thinkphp 框架扩展之类库扩展操作详解
2020/04/23 PHP
正则表达式判断是否存在中文和全角字符和判断包含中文字符串长度
2008/09/27 Javascript
JQuery判断radio(单选框)是否选中和获取选中值方法总结
2015/04/15 Javascript
JQuery中上下文选择器实现方法
2015/05/18 Javascript
picLazyLoad 实现图片延时加载(包含背景图片)
2016/07/21 Javascript
Javascript从数组中随机取出不同元素的两种方法
2016/09/22 Javascript
ES6中的箭头函数实例详解
2017/04/06 Javascript
react路由配置方式详解
2017/08/07 Javascript
vue项目上传Github预览的实现示例
2018/11/06 Javascript
JavaScript提升机制Hoisting详解
2019/10/23 Javascript
html-webpack-plugin修改页面的title的方法
2020/06/18 Javascript
mapboxgl区划标签避让不遮盖实现的代码详解
2020/07/01 Javascript
Python3实现生成随机密码的方法
2014/08/23 Python
Python通过DOM和SAX方式解析XML的应用实例分享
2015/11/16 Python
5分钟 Pipenv 上手指南
2018/12/20 Python
Python爬虫 bilibili视频弹幕提取过程详解
2019/07/31 Python
python绘制动态曲线教程
2020/02/24 Python
Python Dataframe常见索引方式详解
2020/05/27 Python
解决Pytorch自定义层出现多Variable共享内存错误问题
2020/06/28 Python
keras在构建LSTM模型时对变长序列的处理操作
2020/06/29 Python
Grow Gorgeous美国官网:只要八天,体验唤醒毛囊后新生的茂密秀发
2018/06/04 全球购物
英国健身专家:WIT Fitness
2021/02/09 全球购物
巴西购物网站:Onofre Agora
2020/06/08 全球购物
JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
2013/07/02 面试题
观看《永远的雷锋》心得体会
2014/03/12 职场文书
投资合作协议书范本
2014/04/17 职场文书
电钳工人个人求职信
2014/05/10 职场文书
2014年员工工作总结范文
2014/11/18 职场文书
老人院义工活动感想
2015/08/07 职场文书
《卧薪尝胆》读后感3篇
2019/12/26 职场文书
基于angular实现树形二级表格
2021/10/16 Javascript