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 AJAX实现目录浏览与编辑的代码
Oct 21 Javascript
Javascript学习笔记一 之 数据类型
Dec 15 Javascript
EASYUI TREEGRID异步加载数据实现方法
Aug 22 Javascript
JS图片根据鼠标滚动延时加载的实例代码
Jul 13 Javascript
JavaScript生成随机字符串的方法
Mar 19 Javascript
深入理解setTimeout函数和setInterval函数
May 20 Javascript
JavaScript每天必学之数组和对象部分
Sep 17 Javascript
js实现消息滚动效果
Jan 18 Javascript
js仿微信抢红包功能
Sep 25 Javascript
jQuery简单判断值是否存在于数组中的方法示例
Apr 17 jQuery
keep-alive不能缓存多层级路由菜单问题解决
Mar 10 Javascript
vue实现简单图片上传
Jun 30 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
php获取淘宝分类id示例
2014/01/16 PHP
PHP执行shell脚本运行程序不产生core文件的方法
2016/12/28 PHP
PHP7中I/O模型内核剖析详解
2019/04/14 PHP
50个优秀经典PHP算法大集合 附源码
2020/08/26 PHP
JS支持带x身份证号码验证函数
2008/08/10 Javascript
指定区域的图片自动按比例缩小的js代码(防止页面被图片撑破)
2014/02/21 Javascript
移动端H5开发 Turn.js实现很棒的翻书效果
2016/06/20 Javascript
jQuery实现底部浮动窗口效果
2016/09/07 Javascript
自学实现angularjs依赖注入
2016/12/20 Javascript
微信小程序 自定义对话框实例详解
2017/01/20 Javascript
使用bootstrap插件实现模态框效果
2017/05/10 Javascript
简单谈谈React中的路由系统
2017/07/25 Javascript
swiper自定义分页器使用方法详解
2020/09/14 Javascript
vue2中,根据list的id进入对应的详情页并修改title方法
2018/08/24 Javascript
vue 使用自定义指令实现表单校验的方法
2018/08/28 Javascript
Angular动态绑定样式及改变UI框架样式的方法小结
2018/09/03 Javascript
图文详解vue框架安装步骤
2019/02/12 Javascript
layui实现根据table数据判断按钮显示情况的方法
2019/09/26 Javascript
Vue最新防抖方案(必看篇)
2019/10/30 Javascript
Swift 3.0在集合类数据结构上的一些新变化总结
2016/07/11 Python
python安装cx_Oracle模块常见问题与解决方法
2017/02/21 Python
Python 专题五 列表基础知识(二维list排序、获取下标和处理txt文本实例)
2017/03/20 Python
对numpy数据写入文件的方法讲解
2018/07/09 Python
Django csrf 两种方法设置form的实例
2019/02/03 Python
用Python中的turtle模块画图两只小羊方法
2019/04/09 Python
python基于Selenium的web自动化框架
2019/07/14 Python
python3排序的实例方法
2020/10/20 Python
利用python查看数组中的所有元素是否相同
2021/01/08 Python
html5指南-4.使用Geolocation实现定位功能
2013/01/07 HTML / CSS
什么是虚拟内存?虚拟内存有什么优势?
2016/02/09 面试题
环境监测与治理技术专业求职信
2014/07/06 职场文书
反腐倡廉剖析材料
2014/09/30 职场文书
2014年预算员工作总结
2014/12/05 职场文书
挂靠协议书
2015/01/27 职场文书
大学生自我鉴定怎么写
2019/05/07 职场文书