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 学习笔记(九)call和apply方法
Jan 11 Javascript
原生Js实现按的数据源均分时间点幻灯片效果(已封装)
Dec 28 Javascript
jquery中post方法用法实例
Oct 21 Javascript
jQuery中click事件的定义和用法
Dec 20 Javascript
jQuery实现自定义右键菜单的树状菜单效果
Sep 02 Javascript
分享JavaScript与Java中MD5使用两个例子
Dec 23 Javascript
讲解JavaScript的Backbone.js框架的MVC结构设计理念
Feb 14 Javascript
浅谈jQuery中ajaxPrefilter的应用
Aug 01 Javascript
angularjs select 赋值 ng-options配置方法
Feb 28 Javascript
vue项目中跳转到外部链接的实例讲解
Sep 20 Javascript
vue2.0结合Element-ui实战案例
Mar 06 Javascript
微信小程序实现锚点功能
Nov 20 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
Apache, PHP在Windows 9x/NT下的安装与配置 (一)
2006/10/09 PHP
php自动获取目录下的模板的代码
2010/08/08 PHP
体育彩票排列三组选三算法分享
2014/03/07 PHP
mac下Apache + MySql + PHP搭建网站开发环境
2014/06/02 PHP
php基于mcrypt的加密解密实例
2014/10/27 PHP
PHP结合Jquery和ajax实现瀑布流特效
2016/01/07 PHP
老生常谈PHP面向对象之解释器模式
2017/05/17 PHP
BOOM vs RR BO5 第二场 2.14
2021/03/10 DOTA
IE6、IE7中获取Button元素的值的bug说明
2011/08/28 Javascript
JavaScript事件处理器中的event参数使用介绍
2013/05/24 Javascript
基于jquery实现页面滚动到底自动加载数据的功能
2015/12/19 Javascript
Bootstrap如何创建表单
2016/10/21 Javascript
AngularJS实现在ng-Options加上index的解决方法
2016/11/03 Javascript
js判断一个字符串是以某个字符串开头的简单实例
2016/12/27 Javascript
div实现自适应高度的textarea实现angular双向绑定
2017/01/08 Javascript
jQuery Validate 数组 全部验证问题
2017/01/12 Javascript
使用ionic在首页新闻中应用到的跑马灯效果的实现方法
2017/02/13 Javascript
JavaScript学习笔记之函数记忆
2017/09/06 Javascript
mac中利用NVM管理不同node版本的方法详解
2017/11/08 Javascript
JavaScript比较同一天的时间大小实例代码
2018/02/09 Javascript
React 全自动数据表格组件——BodeGrid的实现思路
2019/06/12 Javascript
vue+node 实现视频在线播放的实例代码
2020/10/19 Javascript
Ant Design Vue table中列超长显示...并加提示语的实例
2020/10/31 Javascript
Javascript中的奇葩知识,你知道吗?
2021/01/25 Javascript
Python排序搜索基本算法之希尔排序实例分析
2017/12/09 Python
Python模拟简单电梯调度算法示例
2018/08/20 Python
详解Python list和numpy array的存储和读取方法
2019/11/06 Python
利用python在excel中画图的实现方法
2020/03/17 Python
Python图像识别+KNN求解数独的实现
2020/11/13 Python
Python3中的tuple函数知识点讲解
2021/01/03 Python
10分钟理解CSS3 Grid布局
2018/12/20 HTML / CSS
浅谈react路由传参的几种方式
2021/03/23 Javascript
初二物理教学反思
2014/01/29 职场文书
节约用水标语
2014/06/11 职场文书
学校师德师风整改措施
2014/10/27 职场文书
悬疑名作《朋友游戏》动画无字ED宣传片 新角色公开
2022/04/13 日漫