React中的Ref
React中ref是一个对象,它有一个current属性,可以对这个属性进行操作,用于获取DOM元素和保存变化的值。什么是保存变化的值?就是在组件中,你想保存与组件渲染无关的值,就是JSX中用不到的或不显示到页面上的值,比如setTimeout的返回的ID,就可以把这个值放到ref中。为什么要放到ref中,因为更改ref的值,不会引起组件的重新渲染,因为值与渲染无关,它也不应该引起组件渲染。怎么获取ref对象呢?调用useRef()函数和createRef()函数,它们返回ref对象。在组件的整个生命周期中,ref对象一直存在。组件创建,更准确地说法是,组件挂载,ref对象创建,组件销毁,ref对象销毁。
useRef是一个React Hooks,在函数组件中使用,它还可以接受一个参数,用于初始化useRef返回的对象的current属性。
const ref = useRef(initialValue);
使用useRef获取DOM元素,就是把ref对象赋给react element的ref属性, 每一个react element都有一个ref属性。组件挂载后,ref对象的current属性,就自动指向DOM元素
import React, { useRef } from "react";
const CustomTextInput = () => {
const textInput = useRef();
const focusTextInput = () => textInput.current.focus();
return (
<>
<input type="text" ref={textInput} />
<button onClick={focusTextInput}>Focus the text input</button>
</>
);
}
组件挂载完成,textInput.current指向input输入框,就可以直接调用输入框的focus方法。
使用useRef保存变量的值,直接把变量或值,赋值给ref对象的current属性就可以了。
import React, { useRef, useEffect } from "react";
const Timer = () => {
const intervalRef = useRef();
useEffect(() => {
const id = setInterval(() => {
console.log("A second has passed");
}, 1000);
intervalRef.current = id;
return () => clearInterval(intervalRef.current);
});
const handleCancel = () => clearInterval(intervalRef.current);
return (
<>
//...
</>
);
}
这里要注意的是更新ref对象的值,是一个side effect,因为这个值不参与渲染,更新值是React渲染之外,要做的事情,所以要放到useEffect或useLayoutEffect中,放到事件处理函数中也可以。如果以下有代码
import React, { useRef } from "react";
const RenderCounter = () => {
const counter = useRef(0);
counter.current = counter.current + 1;
return (
<h1>{`The component has been re-rendered ${counter} times`}</h1>
);
};
最好改成
import React, { useRef } from "react";
const RenderCounter = () => {
const counter = useRef(0);
useEffect(() => {
counter.current = counter.current + 1;
});
return (
<h1>{`The component has been re-rendered ${counter} times`}</h1>
);
};
函数组件中也可以使用createRef, 但当使用createRef时,每一次组件渲染时都会创建全新的ref对象,而不是每一次渲染都共用一个ref对象,性能会有问题,再说useRef就是代替createRef的,所以在函数组件中就没有必要使用createRef了。
其实,使用useRef,也可以获取到子组件,直接调用子组件中的方法,不过就是用点麻烦,因为ref只能获取到类组件的实例,也只有类才有实例。函数组件是没有实例的,怎么获取到它?使用forwardref, 把一个函数组件包起来,函数组件就多了一个ref属性。子组件中用useImperativeHandle暴露方法。结合forwardRef 和useImperativeHandle。使用create-react-app 创建React项目,在src中创建一个Counter组件
import React from 'react';
import { useState } from "react" const Counter = () => {
const [count, setCount] = useState(0); const clickHandler = () => {
setCount(c => c + 1);
} return (
<p>count is {count} </p>
)
} export default Counter;
然后在App.js中引入
import React from 'react';
import Counter from "./Counter"; function App() {
return (
<React.Fragment>
<Counter></Counter>
<button>Add</button>
</React.Fragment>
);
} export default App;
此时,如果想点击父组件App中的button来增加子组件的count,怎么办?首先,子组件Counter,要把clickHandler方法暴露出来。做法,1,export的不是组件了,而是forwardRef(组件); 2,组件要接受参数ref,const Counter = (props, ref); 3, 在组件内部,使用useImperativeHandle,它的第一个参数是ref,第二个参数是回调函数,返回一个对象,对象中的属性和方法,就可以在父组件中使用ref获取到。
import React, { forwardRef, useImperativeHandle } from 'react';
import { useState } from "react"
// 组件被forwardRef之后,组件多了一个ref属性
const Counter = (props, ref) => {
const [count, setCount] = useState(0);
const clickHandler = () => {
setCount(c => c + 1);
}
// 第一个参数就是ref,暴露出click方法,供父组件使用
useImperativeHandle(ref, () => {
return ({
click: clickHandler
})
})
return (
<p>count is {count} </p>
)
}
// export forwardRef(组件)
export default forwardRef(Counter);
其次,在父组件App中使用ref,引用子组件,并在button的click回调函数中使用ref
function App() {
const counteRef = useRef();
const handleClick = () => {
counteRef.current.click();
}
return (
<React.Fragment>
<Counter ref={counteRef}></Counter>
<button onClick={handleClick}>Add</button>
</React.Fragment>
);
}
如果项目中使用了Redux和React-Redux,子组件export的是connect()(组件),是一个高阶组件,那父组件中怎么引用子组件呢?如果是react-redux 6.0以前的版本,connect函数第四个参数设置为{ withRef: true },父组件getWrappedInstance()就可以获取到包裹的子组件
connect(null, null, null, { withRef: true })(组件);
如果是react-redux 6.0 以后的版本,使用 forwardRef: true , 代替{ withRef: true },父组件中的ref可以直接获取到包包裹的子组件
connect(null, null, null, { forwardRef: true })(组件);
React中的Ref的更多相关文章
- react中的ref的3种方式
2020-03-31 react中的ref的3种方式 react中ref的3种绑定方式 方式1: string类型绑定 类似于vue中的ref绑定方式,可以通过this.refs.绑定的ref的名字获 ...
- react中的ref在input中的详解
当我们在项目中遇见文本输入框的时候,获取时刻输入框中的值 1.受控组件 class NameForm extends React.Component { constructor(props) { su ...
- 六、React 键盘事件 表单事件 事件对象以及React中的ref获取dom节点 、React实现类似Vue的双向数据绑定
接:https://www.cnblogs.com/chenxi188/p/11782349.html 事件对象 .键盘事件. 表单事件 .ref获取dom节点.React实现类似vue双向数据绑定 ...
- 【Web技术】401- 在 React 中使用 Shadow DOM
本文作者:houfeng 1. Shadow DOM 是什么 Shadow DOM 是什么?我们先来打开 Chrome 的 DevTool,并在 'Settings -> Preferences ...
- React中ref的使用方法
React中ref的使用方法 在react典型的数据流中,props传递是父子组件交互的唯一方式:通过传递一个新的props值来使子组件重新re-render,从而达到父子组件通信.当然,就像reac ...
- vue中:key 和react 中key={} 的作用,以及ref的特性?
vue中:key 和react 中key={} 为了给 vue 或者react 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性 一句话概括就是 ...
- React中Ref 的使用 React-踩坑记_05
React中Ref 的使用 React v16.6.3 在典型的React数据流中,props是父组件与其子组件交互的唯一方式.要修改子项,请使用new props 重新呈现它.但是,在某些情况下,需 ...
- React 中阻止事件冒泡的问题
在正式开始前,先来看看 JS 中事件的触发与事件处理器的执行. JS 中事件的监听与处理 事件捕获与冒泡 DOM 事件会先后经历 捕获 与 冒泡 两个阶段.捕获即事件沿着 DOM 树由上往下传递,到达 ...
- react中input自动聚焦问题
input自动聚焦问题 在react中可以使用refs解决这个问题,首先看一下refs的使用场景: (1)处理焦点.文本选择或媒体控制. (2)触发强制动画. (3)集成第三方 DOM 库. 使用re ...
- react中直接调用子组件的方法(非props方式)
我们都知道在 react中,若要在父组件调用子组件的方法,通常我们会采用在父组件定义一个方法,作为props转给子组件,然后执行该方法,可以获取到子组件传回的参数以得到我们的目的. 显而易见,这个执行 ...
随机推荐
- fastposter v2.9.2 最简海报生成器
fastposter v2.9.2 程序员必备海报生成器 fastposter海报生成器是一款快速开发海报的工具.只需上传一张背景图,在对应的位置放上组件(文字.图片.二维.头像)即可生成海报. 点击 ...
- 5GC 关键技术之网络切片
目录 文章目录 目录 前文列表 网络切片的需求来自于业务对网络提出的差异化要求 基于 3 大业务场景的切片 基于切片资源访问对象的切片 网络切片的商业价值 网络切片的底层技术支撑 网络切片的粒度 网络 ...
- PageOffice 在线编辑 office文件,回调父页面
一.子页面调用父页面的方法 var value=window.external.CallParentFunc("ParentFunName(Arguments);");//父页面的 ...
- kubernetes之python调用
安装 sudo pip3 install kubernetes 认证 首先引入SDK支持库.然后将 ~/.kube 的config文件的内容复制到本地目录,保存为文件kubeconfig.yaml,然 ...
- Python作图三维等高面
技术背景 对于等高线,大家都是比较熟悉的,因为日常生活中遇到的山体和水面,都可以用一系列的等高线描绘出来.而等高面,顾名思义,就是在三维空间"高度一致"的曲面.当然了,在二维平面上 ...
- Kubernetes集群中配置Ingress支持HTTPS访问(一):cfssl
目录 一.系统环境 二.前言 三.对称加密和非对称加密简介 四.什么是HTTPS 五.Ingress简介 六.配置ingress对外发布服务 6.1 安装NGINX ingress controlle ...
- centos7系统的七个运行级别和设置默认运行级别
一.系统七个运行级别概述 0 系统停机模式,系统默认运行级别不能设置为0,否则不能正常启动,机器关的 1 单用户模式,root权限,用于系统维护,禁止远程登陆,就像Windows下的安全模式登录 2 ...
- apache 的下载与配置
一,下载: 打开apache的官方网站,http://www.apache.org/ 拉到网站的最下面,如图所示: 点击HTTP Server链接,对 Apache httpd 2.4.43 Re ...
- .net core DataTable.Load()方法,返回的行缺少,少于reader读出的行
我分析的原因是,datatable模式的schema默认是根据查询的sql来的.起因是我写的sql中带有主键的列,查出来有很多重复值, 然后dt.load会默认把主键重复的行给合并掉,所以最终查询出来 ...
- Linux 系统用户登录时很慢怎么办
第一步:编辑 /etc/ssh/sshd_config 文件 vim /etc/ssh/sshd_config 第二步:搜索 DNS 第三步: 将UseDNS前面的#注释删掉,同时将UseDNS后面的 ...