我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Refs的知识有哪些

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Refs的知识有哪些

本篇内容主要讲解“Refs的知识有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Refs的知识有哪些”吧!

Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。

Refs 使用场景

在某些情况下,我们需要在典型数据流之外强制修改子组件,被修改的子组件可能是一个 React 组件的实例,也可能是一个 DOM 元素,例如:

  •  管理焦点,文本选择或媒体播放。

  •  触发强制动画。

  •  集成第三方 DOM 库。

设置 Refs

1. createRef

支持在函数组件和类组件内部使用

createRef 是 React16.3 版本中引入的。

创建 Refs

使用 React.createRef() 创建 Refs,并通过 ref 属性附加至 React 元素上。通常在构造函数中,将 Refs 分配给实例属性,以便在整个组件中引用。

访问 Refs

当 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中访问。

import React from 'react';  export default class MyInput extends React.Component {      constructor(props) {          super(props);          //分配给实例属性          this.inputRef = React.createRef(null);      }      componentDidMount() {          //通过 this.inputRef.current 获取对该节点的引用          this.inputRef && this.inputRef.current.focus();      }      render() {          //把 <input> ref 关联到构造函数中创建的 `inputRef` 上          return (              <input type="text" ref={this.inputRef}/>          )      }  }

ref 的值根据节点的类型而有所不同:

  •  当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性。

  •  当 ref 属性用于自定义的 class 组件时, ref 对象接收组件的挂载实例作为其 current 属性。

  •  不能在函数组件上使用 ref 属性,因为函数组件没有实例。

总结:为 DOM 添加 ref,那么我们就可以通过 ref 获取到对该DOM节点的引用。而给React组件添加 ref,那么我们可以通过 ref 获取到该组件的实例【不能在函数组件上使用 ref 属性,因为函数组件没有实例】。

2. useRef

仅限于在函数组件内使用

useRef 是 React16.8 中引入的,只能在函数组件中使用。

创建 Refs

使用 React.useRef() 创建 Refs,并通过 ref 属性附加至 React 元素上。

const refContainer = useRef(initialValue);

useRef 返回的 ref 对象在组件的整个生命周期内保持不变。

访问 Refs

当 ref 被传递给 React 元素时,对该节点的引用可以在 ref 的 current 属性中访问。

import React from 'react';  export default function MyInput(props) {      const inputRef = React.useRef(null);      React.useEffect(() => {          inputRef.current.focus();      });      return (          <input type="text" ref={inputRef} />      )  }

关于 React.useRef() 返回的 ref 对象在组件的整个生命周期内保持不变,我们来和 React.createRef() 来做一个对比,代码如下:

import React, { useRef, useEffect, createRef, useState } from 'react';  function MyInput() {      let [count, setCount] = useState(0);      const myRef = createRef(null);      const inputRef = useRef(null);      //仅执行一次      useEffect(() => {          inputRef.current.focus();          window.myRef = myRef;          window.inputRef = inputRef;      }, []);        useEffect(() => {          //除了第一次为true, 其它每次都是 false 【createRef】          console.log('myRef === window.myRef', myRef === window.myRef);          //始终为true 【useRef】          console.log('inputRef === window.inputRef', inputRef === window.inputRef);      })      return (          <>              <input type="text" ref={inputRef}/>              <button onClick={() => setCount(count+1)}>{count}</button>          </>      )  }

3. 回调 Refs

支持在函数组件和类组件内部使用

React 支持 回调 refs 的方式设置 Refs。这种方式可以帮助我们更精细的控制何时 Refs 被设置和解除。

使用 回调 refs 需要将回调函数传递给 React元素 的 ref 属性。这个函数接受 React 组件实例 或 HTML DOM 元素作为参数,将其挂载到实例属性上,如下所示:

import React from 'react';  export default class MyInput extends React.Component {      constructor(props) {          super(props);          this.inputRef = null;          this.setTextInputRef = (ele) => {              this.inputRef = ele;          }      }      componentDidMount() {          this.inputRef && this.inputRef.focus();      }      render() {          return (              <input type="text" ref={this.setTextInputRef}/>          )      }  }

React 会在组件挂载时,调用 ref 回调函数并传入 DOM元素(或React实例),当卸载时调用它并传入 null。在 componentDidMoune 或 componentDidUpdate 触发前,React 会保证 Refs 一定是最新的。

可以在组件间传递回调形式的 refs.

import React from 'react';  export default function Form() {      let ref = null;      React.useEffect(() => {          //ref 即是 MyInput 中的 input 节点          ref.focus();      }, [ref]);      return (          <>              <MyInput inputRef={ele => ref = ele} />              {}          </>      )  }  function MyInput (props) {      return (          <input type="text" ref={props.inputRef}/>      )  }

4. 字符串 Refs(过时API)

函数组件内部不支持使用 字符串 refs [支持 createRef | useRef | 回调 Ref]

function MyInput() {      return (          <>              <input type='text' ref={'inputRef'} />          </>      )  }

Refs的知识有哪些

类组件

通过 this.refs.XXX 获取 React 元素。

class MyInput extends React.Component {      componentDidMount() {          this.refs.inputRef.focus();      }      render() {          return (              <input type='text' ref={'inputRef'} />          )      }  }

Ref 传递

在 Hook 之前,高阶组件(HOC) 和 render props 是 React 中复用组件逻辑的主要手段。

尽管高阶组件的约定是将所有的 props 传递给被包装组件,但是 refs 是不会被传递的,事实上, ref 并不是一个 prop,和 key 一样,它由 React 专门处理。

这个问题可以通过 React.forwardRef (React 16.3中新增)来解决。在 React.forwardRef 之前,这个问题,我们可以通过给容器组件添加 forwardedRef (prop的名字自行确定,不过不能是 ref 或者是 key).

React.forwardRef 之前

import React from 'react';  import hoistNonReactStatic from 'hoist-non-react-statics';  const withData = (WrappedComponent) => {      class ProxyComponent extends React.Component {          componentDidMount() {              //code          }          //这里有个注意点就是使用时,我们需要知道这个组件是被包装之后的组件          //将ref值传递给 forwardedRef 的 prop          render() {              const {forwardedRef, ...remainingProps} = this.props;              return (                  <WrappedComponent ref={forwardedRef} {...remainingProps}/>              )          }      }      //指定 displayName.   未复制静态方法(重点不是为了讲 HOC)      ProxyComponent.displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';      //复制非 React 静态方法      hoistNonReactStatic(ProxyComponent, WrappedComponent);      return ProxyComponent;  }

这个示例中,我们将 ref 的属性值通过 forwardedRef 的 prop,传递给被包装的组件,使用:

class MyInput extends React.Component {      render() {          return (              <input type="text" {...this.props} />          )      }  }  MyInput = withData(MyInput);  function Form(props) {      const inputRef = React.useRef(null);      React.useEffect(() => {          console.log(inputRef.current)      })      //我们在使用 MyInput 时,需要区分其是否是包装过的组件,以确定是指定 ref 还是 forwardedRef      return (          <MyInput forwardedRef={inputRef} />      )  }

React.forwardRef

Ref 转发是一项将 ref 自动地通过组件传递到其一子组件的技巧,其允许某些组件接收 ref,并将其向下传递给子组件。

转发 ref 到DOM中:

import React from 'react';  const MyInput = React.forwardRef((props, ref) => {      return (          <input type="text" ref={ref} {...props} />      )  });  function Form() {      const inputRef = React.useRef(null);      React.useEffect(() => {          console.log(inputRef.current);//input节点      })      return (          <MyInput ref={inputRef} />      )  }
  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2.  调用 React.useRef 创建了一个 React ref 并将其赋值给 ref 变量。

  3.  指定 ref 为JSX属性,并向下传递 <MyInput ref={inputRef}>

  4.  React 传递 ref 给 forwardRef 内函数 (props, ref) => ... 作为其第二个参数。

  5.  向下转发该 ref 参数到 <button ref={ref}>,将其指定为JSX属性

  6.  当 ref 挂载完成,inputRef.current 指向 input DOM节点

注意

第二个参数 ref 只在使用 React.forwardRef 定义组件时存在。常规函数和 class 组件不接收 ref 参数,且 props 中也不存在 ref。

在 React.forwardRef 之前,我们如果想传递 ref 属性给子组件,需要区分出是否是被HOC包装之后的组件,对使用来说,造成了一定的不便。我们来使用 React.forwardRef 重构。

import React from 'react';  import hoistNonReactStatic from 'hoist-non-react-statics';  function withData(WrappedComponent) {      class ProxyComponent extends React.Component {          componentDidMount() {              //code          }          render() {              const {forwardedRef, ...remainingProps} = this.props;              return (                  <WrappedComponent ref={forwardedRef} {...remainingProps}/>              )          }      }        //我们在使用被withData包装过的组件时,只需要传 ref 即可      const forwardRef = React.forwardRef((props, ref) => (          <ProxyComponent {...props} forwardedRef={ref} />      ));      //指定 displayName.      forwardRef.displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';      return hoistNonReactStatic(forwardRef, WrappedComponent);  }
class MyInput extends React.Component {      render() {          return (              <input type="text" {...this.props} />          )      }  }  MyInput.getName = function() {      console.log('name');  }  MyInput = withData(MyInput);  console.log(MyInput.getName); //测试静态方法拷贝是否正常  function Form(props) {      const inputRef = React.useRef(null);      React.useEffect(() => {          console.log(inputRef.current);//被包装组件MyInput      })      //在使用时,传递 ref 即可      return (          <MyInput ref={inputRef} />      )  }

react-redux 中获取子组件(被包装的木偶组件)的实例

旧版本中(V4 / V5)

我们知道,connect 有四个参数,如果我们想要在父组件中子组件(木偶组件)的实例,那么需要设置第四个参数 options 的 withRef 为 true。随后可以在父组件中通过容器组件实例的 getWrappedInstance() 方法获取到木偶组件(被包装的组件)的实例,如下所示:

//MyInput.js  import React from 'react';  import { connect } from 'react-redux';  class MyInput extends React.Component {      render() {          return (              <input type="text" />          )      }  }  export default connect(null, null, null, { withRef: true })(MyInput);
//index.js  import React from "react";  import ReactDOM from "react-dom";  import { createStore } from 'redux';  import { Provider } from 'react-redux';  import MyInput from './MyInput';  function reducer(state, action) {      return state;  }  const store = createStore(reducer);  function Main() {      let ref = React.createRef();      React.useEffect(() => {          console.log(ref.current.getWrappedInstance());      })      return (          <Provider store={store}>              <MyInput ref={ref} />          </Provider>      )  }  ReactDOM.render(<Main />, document.getElementById("root"));

这里需要注意的是:MyInput 必须是类组件,而函数组件没有实例,自然也无法通过 ref 获取其实例。react-redux 源码中,通过给被包装组件增加 ref 属性,getWrappedInstance 返回的是该实例 this.refs.wrappedInstance。

if (withRef) {      this.renderedElement = createElement(WrappedComponent, {          ...this.mergedProps,          ref: 'wrappedInstance'      })  }

新版本(V6 / V7)

react-redux新版本中使用了 React.forwardRef方法进行了 ref 转发。 自 V6 版本起,option 中的 withRef 已废弃,如果想要获取被包装组件的实例,那么需要指定 connect 的第四个参数 option 的 forwardRef 为 true,具体可见下面的示例:

//MyInput.js 文件  import React from 'react';  import { connect } from 'react-redux';  class MyInput extends React.Component {      render() {          return (              <input type="text" />          )      }  }  export default connect(null, null, null, { forwardRef: true })(MyInput);

直接给被包装过的组件增加 ref,即可以获取到被包装组件的实例,如下所示:

//index.js  import React from "react";  import ReactDOM from "react-dom";  import { createStore } from 'redux';  import { Provider } from 'react-redux';  import MyInput from './MyInput';  function reducer(state, action) {      return state;  }  const store = createStore(reducer);  function Main() {      let ref = React.createRef();      React.useEffect(() => {          console.log(ref.current);      })      return (          <Provider store={store}>              <MyInput ref={ref} />          </Provider>      )  }  ReactDOM.render(<Main />, document.getElementById("root"));

同样,MyInput 必须是类组件,因为函数组件没有实例,自然也无法通过 ref 获取其实例。

react-redux 中将 ref 转发至 Connect 组件中。通过 forwardedRef 传递给被包装组件 WrappedComponent 的 ref。 

if (forwardRef) {        const forwarded = React.forwardRef(function forwardConnectRef(            props,            ref        ) {            return <Connect {...props} forwardedRef={ref} />        })        forwarded.displayName = displayName        forwarded.WrappedComponent = WrappedComponent        return hoistStatics(forwarded, WrappedComponent)    }    //...    const { forwardedRef, ...wrapperProps } = props    const renderedWrappedComponent = useMemo(        () => <WrappedComponent {...actualChildProps} ref={forwardedRef} />,       [forwardedRef, WrappedComponent, actualChildProps]  )

到此,相信大家对“Refs的知识有哪些”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Refs的知识有哪些

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SwiftUI的知识点有哪些

这篇文章主要讲解了“SwiftUI的知识点有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SwiftUI的知识点有哪些”吧!一、背景苹果于2019年度WWDC全球开发者大会上,发布了基于
2023-06-04

React的知识点有哪些

这篇文章主要介绍了React的知识点有哪些的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇React的知识点有哪些文章都会有所收获,下面我们一起来看看吧。  组件的数据挂载方式,属性(props)props是正常
2023-06-03

yolov5的知识点有哪些

这篇文章主要讲解了“yolov5的知识点有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“yolov5的知识点有哪些”吧!一、yolo中txt文件的说明:二、yolo跑视频、图片文件的格式
2023-07-02

ECharts的知识点有哪些

本文小编为大家详细介绍“ECharts的知识点有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“ECharts的知识点有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。简介ECharts(Enterpris
2023-06-27

HTML5的知识点有哪些

这篇文章主要讲解了“HTML5的知识点有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“HTML5的知识点有哪些”吧!1 :基于HTML5的移动Web应用Canvas绘图:通过获取HTML
2023-06-17

JavaScript8的知识点有哪些

这篇文章主要介绍“JavaScript8的知识点有哪些”,在日常操作中,相信很多人在JavaScript8的知识点有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaScript8的知识点有哪些”的疑
2023-06-27

Vue的知识点有哪些

本篇内容介绍了“Vue的知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.官方介绍Vue (读音 /vjuː/,类似于 view
2023-06-03

django知识点有哪些

小编给大家分享一下django知识点有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、视图函数:请求对象-----------request:1、HttpR
2023-06-04

HBase知识点有哪些

本篇内容介绍了“HBase知识点有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!HBase – Hadoop Database,是一个高
2023-06-02

vue知识点有哪些

这篇文章主要为大家展示了“vue知识点有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“vue知识点有哪些”这篇文章吧。一、前端核心分析1.1、概述Soc原则:关注点分离原则Vue 的核心库只
2023-06-22

编程热搜

目录