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 18 Javascript
filters.revealTrans.Transition使用方法小结
Aug 19 Javascript
前端微信支付js代码
Jul 25 Javascript
分享JS数组求和与求最大值的方法
Aug 11 Javascript
js HTML5 Canvas绘制转盘抽奖
Sep 13 Javascript
各式各样的导航条效果css3结合jquery代码实现
Sep 17 Javascript
详解vuex 中的 state 在组件中如何监听
May 23 Javascript
基于daterangepicker日历插件使用参数注意的问题
Aug 10 Javascript
微信小程序返回多级页面的实现方法
Oct 27 Javascript
不使用JavaScript实现菜单的打开和关闭效果demo
May 01 Javascript
vue2实现搜索结果中的搜索关键字高亮的代码
Aug 29 Javascript
JavaScript实现网页动态生成表格
Nov 25 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
基于mysql的bbs设计(二)
2006/10/09 PHP
一贴学会PHP 新手入门教程
2009/08/03 PHP
php版微信返回用户text输入的方法
2016/11/14 PHP
详细解读php的命名空间(二)
2018/02/21 PHP
Aster vs KG BO3 第三场2.18
2021/03/10 DOTA
发两个小东西,ASP/PHP 学习工具。 用JavaScript写的
2007/04/12 Javascript
jQuery-ui中自动完成实现方法
2010/06/10 Javascript
基于jQuery实现的Ajax 验证用户名是否存在的实现代码
2011/04/06 Javascript
基于jquery的lazy loader插件实现图片的延迟加载[简单使用]
2011/05/07 Javascript
js字符串的各种格式的转换 ToString,Format
2011/08/08 Javascript
Javascript面向对象设计一 工厂模式
2011/12/20 Javascript
利用js实现禁止复制文本信息
2015/06/03 Javascript
javascript中Date format(js日期格式化)方法小结
2015/12/17 Javascript
微信小程序 向左滑动删除功能的实现
2017/03/10 Javascript
NodeJs实现定时任务的示例代码
2017/12/05 NodeJs
webpack 单独打包指定JS文件的方法
2018/02/22 Javascript
使用vue制作探探滑动堆叠组件的实例代码
2018/03/07 Javascript
浅谈 Webpack 如何处理图片(开发、打包、优化)
2019/05/15 Javascript
Element Popover 弹出框的使用示例
2020/07/26 Javascript
Python基于回溯法子集树模板解决选排问题示例
2017/09/07 Python
基于Python的微信机器人开发 微信登录和获取好友列表实现解析
2019/08/21 Python
python numpy中cumsum的用法详解
2019/10/17 Python
浅析Python面向对象编程
2020/07/10 Python
理解Django 中Call Stack机制的小Demo
2020/09/01 Python
jupyter 添加不同内核的操作
2021/02/06 Python
一款基于css3的动画按钮代码教程
2014/11/23 HTML / CSS
H5混合开发app如何升级的方法
2018/01/10 HTML / CSS
介绍一下grep命令的使用
2012/06/28 面试题
母婴店促销方案
2014/03/05 职场文书
大学生求职信
2014/06/17 职场文书
赵乐秦在党的群众路线教育实践活动总结大会上的讲话稿
2014/10/25 职场文书
公司车辆管理制度
2015/08/04 职场文书
孩子满月酒答谢词
2015/09/30 职场文书
2016中学教师读书心得体会
2016/01/13 职场文书
SQL之各种join小结详细讲解
2021/08/04 MySQL
mysql幻读详解实例以及解决办法
2022/06/16 MySQL