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实现简单二级下拉菜单实例
Jun 15 Javascript
JavaScript中的ArrayBuffer详细介绍
Dec 08 Javascript
jQuery类选择器用法实例
Dec 23 Javascript
jQuery实现跟随鼠标运动图层效果的方法
Feb 02 Javascript
js实现接收表单的值并将值拼在表单action后面的方法
Nov 23 Javascript
Winform客户端向web地址传参接收参数的方法
May 17 Javascript
快速掌握jQuery插件WebUploader文件上传
Nov 07 Javascript
node.js中cluster的使用教程
Jun 09 Javascript
JS中type=&quot;button&quot;和type=&quot;submit&quot;的区别
Jul 04 Javascript
vue 项目 iOS WKWebView 加载
Apr 17 Javascript
详解将微信小程序接口Promise化并使用async函数
Aug 05 Javascript
vue中重定向redirect:‘/index‘,不显示问题、跳转出错的完美解决
Sep 28 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 的 like 问题,超强毕杀记!!!
2007/01/18 PHP
php结合飞信 免费天气预报短信
2009/05/07 PHP
jQuery 处理网页内容的实现代码
2010/02/15 Javascript
基于jquery的网页SELECT下拉框美化代码
2010/10/28 Javascript
远离JS灾难css灾难之 js私有函数和css选择器作为容器
2011/12/11 Javascript
DOM操作一些常用的属性汇总
2015/03/13 Javascript
AngularJS控制器详解及示例代码
2016/08/16 Javascript
清除js缓存的多种方法总结
2016/12/09 Javascript
Bootstrap栅格系统使用方法及页面调整变形的解决方法
2017/03/10 Javascript
微信小程序登录态控制深入分析
2017/04/12 Javascript
ReactNative之键盘Keyboard的弹出与消失示例
2017/07/11 Javascript
用Vue.extend构建消息提示组件的方法实例
2017/08/08 Javascript
vue组件间通信子与父详解(二)
2017/11/07 Javascript
深入理解Vue Computed计算属性原理
2018/05/29 Javascript
jQuery解析json格式数据示例
2018/09/01 jQuery
解决layer 动态加载select 失效的问题
2019/09/18 Javascript
vue实现移动端拖动排序
2020/08/21 Javascript
Nodejs 数组的队列以及forEach的应用详解
2021/02/25 NodeJs
[02:28]PWL开团时刻DAY3——Ink Ice与DeMonsTer之间的勾心斗角
2020/11/03 DOTA
Python之os操作方法(详解)
2017/06/15 Python
关于pytorch多GPU训练实例与性能对比分析
2019/08/19 Python
Scrapy框架介绍之Puppeteer渲染的使用
2020/06/19 Python
使用python-cv2实现视频的分解与合成的示例代码
2020/10/26 Python
Python创建文件夹与文件的快捷方法
2020/12/08 Python
IE兼容css3圆角的实现代码
2011/07/21 HTML / CSS
CSS3制作皮卡丘动画壁纸的示例
2020/11/02 HTML / CSS
HTML5页面直接调用百度地图API获取当前位置直接导航目的地的实现代码
2018/03/02 HTML / CSS
Canvas 帧动画吃苹果小游戏
2020/08/05 HTML / CSS
LightInTheBox西班牙站点:全球商品在线采购
2016/09/22 全球购物
添柏岚英国官方网站:Timberland英国
2019/11/28 全球购物
机械制造与自动化应届生求职信
2013/11/16 职场文书
你懂得怎么写自荐信吗?
2013/12/27 职场文书
消防器材管理制度
2014/01/28 职场文书
银行职员个人的工作自我评价
2014/02/15 职场文书
2015新年寄语大全
2014/12/08 职场文书
推荐信范文大全
2015/03/27 职场文书