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 相关文章推荐
通过JS 获取Mouse Position(鼠标坐标)的代码
Sep 21 Javascript
JS左右无缝滚动(一般方法+面向对象方法)
Aug 17 Javascript
JS 添加网页桌面快捷方式的代码详细整理
Dec 27 Javascript
javascrip关于继承的小例子
May 10 Javascript
JavaScript中的console.trace()函数介绍
Dec 29 Javascript
JavaScript中利用jQuery绑定事件的几种方式小结
Mar 06 Javascript
JavaScript队列、优先队列与循环队列
Nov 14 Javascript
Vue.js手风琴菜单组件开发实例
May 16 Javascript
二维码图片生成器QRCode.js简单介绍
Aug 18 Javascript
原生JS实现$.param() 函数的方法
Aug 10 Javascript
微信小程序实现打卡日历功能
Sep 21 Javascript
JavaScript实现筛选数组
Mar 02 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面向对象三大特点学习(充分理解抽象、封装、继承、多态)
2012/05/07 PHP
Win2003+apache+PHP+SqlServer2008 配置生产环境
2014/07/29 PHP
实例讲解YII2中多表关联的使用方法
2017/07/21 PHP
PHP实现将多个文件压缩成zip格式并下载到本地的方法示例
2018/05/23 PHP
php 使用expat方式解析xml文件操作示例
2019/11/26 PHP
php利用ZipArchive类操作文件的实例
2020/01/21 PHP
fireworks菜单生成器mm_menu.js在 IE 7.0 显示问题的解决方法
2009/10/20 Javascript
兼容各大浏览器的JavaScript阻止事件冒泡代码
2015/07/09 Javascript
Hallo.js基于jQuery UI所见即所得的Web编辑器
2016/01/26 Javascript
基于JavaScript判断浏览器到底是关闭还是刷新(超准确)
2016/02/01 Javascript
详解JavaScript对象类型
2016/06/16 Javascript
用headjs来管理和加载js 提高网站加载速度
2016/11/29 Javascript
jquery实现转盘抽奖功能
2017/01/06 Javascript
详解webpack es6 to es5支持配置
2017/05/04 Javascript
js自定义瀑布流布局插件
2017/05/16 Javascript
vue路由跳转时判断用户是否登录功能的实现
2017/10/26 Javascript
浅谈实现vue2.0响应式的基本思路
2018/02/13 Javascript
JS实现520 表白简单代码
2018/05/21 Javascript
分享5个顶级的JavaScript Ajax组件库
2018/09/16 Javascript
Puppeteer 爬取动态生成的网页实战
2018/11/14 Javascript
从零开始在NPM上发布一个Vue组件的方法步骤
2018/12/20 Javascript
在react中使用vue的状态管理的方法示例
2020/05/02 Javascript
JS绘图Flot应用图形绘制异常解决方案
2020/10/16 Javascript
python调用cmd命令行制作刷博器
2014/01/13 Python
玩转python爬虫之正则表达式
2016/02/17 Python
Python的Tornado框架实现异步非阻塞访问数据库的示例
2016/06/30 Python
使用pandas模块读取csv文件和excel表格,并用matplotlib画图的方法
2018/06/22 Python
英国最大的运动营养公司之一:LA Muscle
2018/07/02 全球购物
伦敦一家领先的精品零售商:IRIS Fashion
2019/05/24 全球购物
会计专业的自荐信
2013/12/12 职场文书
房产公证书范本
2014/04/10 职场文书
机关作风建设工作总结
2014/10/23 职场文书
2014年旅游局法制宣传日活动总结
2014/11/01 职场文书
离婚协议书样本
2015/01/26 职场文书
写给同学的新学期寄语
2015/02/27 职场文书
2015年学校总务处工作总结
2015/05/19 职场文书