React forwardRef的使用方法及注意点

之前使用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元素实例

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组件实例

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使用的资料请关注我们其它相关文章!

(0)

相关推荐

  • 在react项目中使用antd的form组件,动态设置input框的值

    问题: 创建账号时,输入账号后不搜索直接保存,提示查询后,再点搜索就不能搜索这个账号了 原因: 点击保存之后,对表单进行了验证,导致之后请求的数据无法在更新到input框中,也就是说即使在state中有值,也不会更新initialValue值,就导致搜索后的值不能正确填入input中,表单也就提交不了. 解决办法: 不使用initialValue设置动态更新的值,而是使用 this.props.form.setFieldValue({name:data}); 用于动态更新值,就可以解决了. if

  • react中Suspense的使用详解

    关于Suspense的使用,先来看下示例代码 const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> </div&

  • React中Ref 的使用方法详解

    本文实例讲述了React中Ref 的使用方法.分享给大家供大家参考,具体如下: React中Ref 的使用 React v16.6.3 在典型的React数据流中,props是父组件与其子组件交互的唯一方式.要修改子项,请使用new props 重新呈现它.但是,在某些情况下,需要在典型数据流之外强制修改子项.要修改的子项可以是React组件的实例,也可以是DOM元素.对于这两种情况,React都提供了api. 何时使用refs refs有一些很好的用例: 1.文本选择或媒体播放. 2.触发势在

  • 使用VScode 插件debugger for chrome 调试react源码的方法

    代码调试,是我们前端日常工作中不可或缺的能力了吧! 在面向dom开发的时代,我们开发时直接在chrome里打断点是很方便的. 但是,当我们面向组件开发时(react),浏览器拿到的是我们编译过后的代码,还想在浏览器里打断点几乎是不可能的了. 场景 那怎么办,方法总是比困难多!愚蠢的我想到了console/debugger!!一直在使用,虽然很不方便(打印太多实在太乱!上线还要配置删除掉),但是我竟然使用了很久(这真是一个糟糕的编码习惯吧).直到今天,我想研究一下react源码,需要断点的地方有很

  • 使用webpack5从0到1搭建一个react项目的实现步骤

    前言 在这之前,每开始一个新项目我都是使用现有的脚手架,这非常便于快速地启动一个新项目,而且通用的脚手架通常考虑地更加全面,也有利于项目的稳定开发:不过对于一个小项目,根据需求自己搭建可能会更好,一方面小项目不需要脚手架那么丰富的功能,另一方面可以提高对项目的掌控度以方便后期的扩展. 这篇文章是在实践中总结的,具有实操性,读者可跟着一步步进行搭建,中间我会穿插一些原理,当然因为笔者的能力有限,不会特别深入. 预备知识 熟悉Javascript && HTML && CSS

  • React forwardRef的使用方法及注意点

    之前使用react.forwardRef始终无法应用于react高阶组件中,最近终于捣鼓出来了,于是记录下来.关键点就是React.forwardRef的API中ref必须指向dom元素而不是React组件. React.forwardRef使用示例 下面就是应用到React组件的错误示例: const A=React.forwardRef((props,ref)=><B {...props} ref={ref}/>) 这就是我之前经常犯的错误, 这里的ref是无法生效的. 前面提到re

  • Webpack 4.x搭建react开发环境的方法步骤

    本文介绍了了Webpack 4.x搭建react开发环境的方法步骤,分享给大家,也给自己留个笔记 必要依赖一览(npm install) 安装好. "dependencies": { "babel-core": "^6.26.3", "babel-loader": "^7.1.5", "babel-preset-env": "^1.7.0", "react&

  • 详解React路由传参方法汇总记录

    React中传参方式有很多,通过路由传参的方式也是必不可少的一种. 本文记录项目中会用到的路由传参方式: 路由跳转传参API + 目标路由获取参数的方式. 一.动态路由 跳转方法 Link <Link to={{ pathname: "/user/add/1" }}>跳转新增页面</Link> history.push this.props.history.push("/user/add/1"); 获参方法 this.props.match.

  • Electron集成React和Vue流程方法讲解

    目录 集成React 1. 热调试 2. 打包 集成Vue 集成React 1. 热调试 在React项目目录下安装Electron npm install electron 修改package.json文件,增加或将已有的main属性值修改为main.js,在scriptes中添加"electron-start": "electron .",最终配置文件如下: { "name": "electron-react", &quo

  • React网络请求发起方法详细介绍

    目录 1. 发起网络请求 2. 开发时网络请求代理配置 1. 发起网络请求 首先需要安装 axios 库: yarn add axios 发起网络请求: import React, { Component } from 'react' import { get } from './utils/http' import Loading from './components/Loading' class App extends Component { state = { users: null }

  • React浅析Fragments使用方法

    目录 概述 动机 短语法 带key 的Fragments 概述 可以将子列表分组,而无需向DOM添加额外节点 简单理解:空标签 <React.Fragment></React.Fragment> 或 <></> render() { return ( <React.Fragment> <ChildA /> <ChildB /> <ChildC /> </React.Fragment> ) } 动机

  • Electron打包React生成桌面应用方法详解

    目录 一.Electron简介 二.搭建准备 三.创建基本应用程序 四.打包项目 一.Electron简介 Electron是一个能让你使用JavaScript,HTML和CSS来创建桌面应用程序的框架.这些应用程序可以打包后在 macOS.Windows 和 Linux 上直接运行. 在目前浏览器和移动端盛行的互联网环境下,跨平台的桌面应用开发,也为前端提供了一个新分支方向. 二.搭建准备 1.检查git和node是否安装完成 git --versionnode -vnpm -v 2.搭建Re

  • 详解React hooks组件通信方法

    目录 一.前言 二.父子组件通信 1)父组件传值给子组件 2)子组件传值给父组件 3)跨组件传值(父传孙子组件) 一.前言 组件通信是React中的一个重要的知识点,下面列举一下 react hooks中常用的父子.跨组件通信的方法 二.父子组件通信 1)父组件传值给子组件 子组件代码: //子组件 const Child = ({ param1, param2 }) => { return <>父组件传递的参数:{param1},{param2}</> } param1.p

  • nginx配置React静态页面的方法教程

    前言 本文主要给大家介绍了关于nginx配置React静态页面的相关内容,文中给大家详细介绍了关于nginx的安装以及一些基本操作,然后给大家分享了React 静态页面 nginx 配置简洁版的示例代码,下面话不多说了,来一起看看详细的介绍吧. 关于nginx的安装启动以及80端口被占用的解决方法,大家也可以参考这篇文章:http://www.jb51.net/article/110291.htm 第一步:安装 1.http://nginx.org/en/download.html 下载 2.t

  • 使用webpack搭建react开发环境的方法

    1.初始化项目 mkdir react-redux && cd react-redux npm init -y 2.安装webpack npm i webpack -D npm i -D 是 npm install --save-dev 的简写,是指安装模块并保存到 package.json 的 devDependencies中,主要在开发环境中的依赖包. 如果使用webpack 4+ 版本,还需要安装 CLI. npm install -D webpack webpack-cli 3.新

随机推荐