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 实用函数的使用详解
May 10 Javascript
js实现全屏漂浮广告移入光标停止移动
Dec 02 Javascript
JavaScript字符串对象toLowerCase方法入门实例(用于把字母转换为小写)
Oct 17 Javascript
JS限制文本框只能输入数字和字母方法
Feb 28 Javascript
JavaScript 表单处理实现代码
Apr 13 Javascript
js添加绑定事件的方法
May 15 Javascript
JS实现的倒计时恢复按钮点击功能【可用于协议阅读倒计时】
Apr 19 Javascript
Koa2微信公众号开发之本地开发调试环境搭建
May 16 Javascript
自定义javascript验证框架示例【附源码下载】
May 31 Javascript
vue-cli3添加模式配置多环境变量的方法
Jun 05 Javascript
改变layer confirm弹窗按钮的颜色方法
Sep 12 Javascript
jenkins自动构建发布vue项目的方法步骤
Jan 04 Vue.js
原生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 jquery 实现新闻标签分类与无刷新分页
2009/12/18 PHP
PHP中source #N问题的解决方法
2014/01/27 PHP
php像数组一样存取和修改字符串字符
2014/03/21 PHP
PHP实现股票趋势图和柱形图
2015/02/07 PHP
php解析mht文件转换成html的实例
2017/03/13 PHP
laravel 字段格式化 modle 字段类型转换方法
2019/09/30 PHP
Laravel实现ApiToken认证请求
2019/10/14 PHP
JS 文字符串转换unicode编码函数
2009/05/30 Javascript
简单纯js实现点击切换TAB标签实例
2015/08/23 Javascript
jQuery mobile的header和footer在点击屏幕的时候消失的解决办法
2016/07/01 Javascript
使用jQuery的ajax方法向服务器发出get和post请求的方法
2017/01/13 Javascript
vue2.0中click点击当前li实现动态切换class
2017/06/21 Javascript
vue中的计算属性的使用和vue实例的方法示例
2017/12/04 Javascript
JavaScript 中 JSON.parse 函数 和 JSON.stringify 函数
2018/12/05 Javascript
vue.js中使用微信扫一扫解决invalid signature问题(完美解决)
2020/04/11 Javascript
详解Vue3中对VDOM的改进
2020/04/23 Javascript
微信小程序开发数据缓存基础知识辨析及运用实例详解
2020/11/06 Javascript
JavaScript实现前端倒计时效果
2021/02/09 Javascript
[01:15:15]VG VS EG Supermajor小组赛B组胜者组第一轮 BO3第二场 6.2
2018/06/03 DOTA
在Python的Tornado框架中实现简单的在线代理的教程
2015/05/02 Python
Python3的urllib.parse常用函数小结(urlencode,quote,quote_plus,unquote,unquote_plus等)
2016/09/18 Python
python如何求解两数的最大公约数
2018/09/27 Python
Python使用gRPC传输协议教程
2018/10/16 Python
python写文件时覆盖原来的实例方法
2020/07/22 Python
HTML5 的新的表单元素(datalist/keygen/output)使用介绍
2013/07/19 HTML / CSS
丝芙兰法国官网:SEPHORA法国
2016/09/01 全球购物
自荐信格式范文
2013/10/07 职场文书
《猴子种果树》教学反思
2014/04/26 职场文书
大学第二课堂活动总结
2014/07/08 职场文书
会计工作总结范文2014
2014/12/23 职场文书
公证处委托书
2015/01/28 职场文书
医德医风自我评价2015
2015/03/03 职场文书
清明祭英烈活动总结
2015/05/11 职场文书
厉行节约工作总结
2015/08/12 职场文书
导游词之山西祁县乔家大院
2019/10/14 职场文书
python自然语言处理之字典树知识总结
2021/04/25 Python