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 相关文章推荐
网站上面有这种切换效果
Jun 26 Javascript
jquery 1.4.2发布!主要是性能与API
Feb 25 Javascript
JS弹出窗口代码大全(详细整理)
Dec 21 Javascript
js获取客户端网卡的IP地址、MAC地址
Mar 26 Javascript
js获取select默认选中的Option并不是当前选中值
May 07 Javascript
jQuery实用技巧必备(中)
Nov 03 Javascript
jquery对象和DOM对象的相互转换详解
Oct 18 Javascript
jQuery插件FusionCharts绘制的2D帕累托图效果示例【附demo源码】
Mar 28 jQuery
react.js使用webpack搭配环境的入门教程
Aug 14 Javascript
Redux实现组合计数器的示例代码
Jul 04 Javascript
JavaScript常见JSON操作实例分析
Aug 08 Javascript
利用js实现简易红绿灯
Oct 15 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
复杂检索数据并分页显示的处理方法
2006/10/09 PHP
解析php根据ip查询所在地区(非常有用,赶集网就用到)
2013/07/01 PHP
php 强制下载文件实现代码
2013/10/28 PHP
YII路径的用法总结
2014/07/09 PHP
WordPress后台中实现图片上传功能的实例讲解
2016/01/11 PHP
PHP7标量类型declare用法实例分析
2016/09/26 PHP
简单谈谈PHP面向对象之标识对象
2017/06/27 PHP
微信公众号开发之获取位置信息php代码
2018/06/13 PHP
网络图片延迟加载实现代码 超越jquery控件
2010/03/27 Javascript
判断输入是否为空,获得输入类型的JS代码
2013/10/30 Javascript
JavaScript实现Java中StringBuffer的方法
2015/02/09 Javascript
利用vue开发一个所谓的数独方法实例
2017/12/21 Javascript
express+mockjs实现模拟后台数据发送功能
2018/01/07 Javascript
JS中Map和ForEach的区别
2018/02/05 Javascript
vue中的provide/inject的学习使用
2018/05/09 Javascript
Vue文件配置全局变量的实例
2018/09/06 Javascript
Vue页面跳转动画效果的实现方法
2018/09/23 Javascript
自定义Vue组件打包、发布到npm及使用教程
2019/05/22 Javascript
redux处理异步action解决方案
2020/03/22 Javascript
Python时间戳与时间字符串互相转换实例代码
2013/11/28 Python
Python常用的爬虫技巧总结
2016/03/28 Python
python实现多线程的两种方式
2016/05/22 Python
python中获得当前目录和上级目录的实现方法
2017/10/12 Python
python如何使用unittest测试接口
2018/04/04 Python
Python使用pylab库实现绘制直方图功能示例
2018/06/01 Python
python监测当前联网状态并连接的实例
2018/12/18 Python
python采集微信公众号文章
2018/12/20 Python
Python基础之文件读取的讲解
2019/02/16 Python
对Python 中矩阵或者数组相减的法则详解
2019/08/26 Python
Python学习笔记之装饰器
2020/08/06 Python
南非领先的在线旅行社:Travelstart南非
2016/09/04 全球购物
日本最佳原创设计品牌:Felissimo(芬理希梦)
2019/03/19 全球购物
什么是数据抽象
2016/11/26 面试题
Shell编程面试题
2016/05/29 面试题
材料加工硕士生求职信
2013/10/10 职场文书
2014年平安建设工作总结
2014/11/19 职场文书