React的哲学是在JS层面构建UI,并把UI组件以功能单位拆分成更小的组件单元,以利于复用和整合,父组件通过props作为操作子组件的唯一通道,甚至子组件想和父组件交互时,也只能依靠父组件通过props传递下来的方法(该方法在父组件内定义,子组件只是拿到它的引用)。在文档中,称这种模式属于dataflow,即把程序分成多个块,每个块相对独立,并有各自的处理逻辑(参考维基的,暂且这么理解)。

在React中,考虑到有些场景通过直接获取元素的引用会更方便简洁,于是提供了Ref这个接口。Ref可以帮我们获取React Element或DOM Element的引用,在文档提到:

When to Use Refs

There are a few good use cases for refs:

  • Managing focus, text selection, or media playback.  //操作元素的焦点、文本选择和媒体播放
  • Triggering imperative animations.                              //触发必要的动画效果
  • Integrating with third-party DOM libraries.                 //整合进第三方的DOM插件时

可以看出,这些场景都是想获取文档中的某个元素并触发摸个行为。在组件构建起来变得复杂时,可能元素众多,要获取/改变某个特定元素,要么经过几层筛选,要么传递的props变得臃肿,ref就像一个id,提供了简洁的接口和回调机制。

同时,文档也提醒不要滥用ref,推荐只作为一种辅佐手段。

Avoid using refs for anything that can be done declaratively.

For example, instead of exposing open() and close() methods on a Dialog component, pass an isOpen prop to it.

ref使用:

第一个例子,ref将DOM元素的引用存储到组件的一个内部变量中。

   focus() {
// Explicitly focus the text input using the raw DOM API
this.textInput.focus();
} render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in an instance field (for example, this.textInput).
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input; }} />
<input
type="button"
value="Focus the text input"
onClick={this.focus}
/>
</div>
);
}

在line13中,ref作为一个html特性插入到input中,它的值是一个函数。该函数在组件挂载的时候触发,函数的唯一参数是组件本身(也就是这个input元素),函数体内用一个变量this.textInput指向了该input。

在组件从文档中卸载的时候,函数会再次触发,此时参数是null。也即是将this.textInput赋值为null,随后被js的垃圾收集机制清除。这是文档推荐的方式,单纯获取一个元素的引用。

第二个例子,ref将自定义class组件的引用存储到组件的一个内部变量中。

 class AutoFocusTextInput extends React.Component {
componentDidMount() {
this.textInput.focus();
} render() {
return (
<CustomTextInput
ref={(input) => { this.textInput = input; }} />
);
}
}

当ref所在的是一个自定义的class组件时,其函数参数是class组件本身。

第二个例子,ref不能用在Functional组件上,因为他们不会生成组件实例,一般而言他们只是返回JSX。只有class组件会生成带props和state的组件实例。

 function MyFunctionalComponent() {
return <input />;
} class Parent extends React.Component {
render() {
// This will *not* work!
return (
<MyFunctionalComponent
ref={(input) => { this.textInput = input; }} />
);
}
}

除非把functional component 转换成classcomponent

但是,我们可以在functional组件的内部使用ref,这和上面是不一样的:

 function CustomTextInput(props) {
// textInput must be declared here so the ref callback can refer to it
let textInput = null; function handleClick() {
textInput.focus();
} return (
<div>
<input
type="text"
ref={(input) => { textInput = input; }} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}

要注意:

这里的ref将当前的input传给了function内部的一个变量,所以function内部的handle方法可以引用到它。

而前面的例子中,<MyFunctionalComponent>只是function返回到Parent组件内的一段JSX,其ref将input传给了Parent内部的变量。

----------------------------------------------------------------

特殊场景:

当我们想在父组件中获取子组件的某个DOM节点时~~~~~虽然这是不推荐的,但是React还是提供了一种方式:

将一个ref回调函数作为props传给子组件,并在子组件的目标节点中作为元素的ref的回调。

 function CustomTextInput(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
} class Parent extends React.Component {
render() {
return (
<CustomTextInput
inputRef={el => this.inputElement = el}
/>
);
}
}

这时候,子元素中的目标节点就作为父组件ref函数的参数,并被传给父组件的内部变量this.inputElement。

这种方式对functional 组件返回的JSX也有效,毕竟获取元素引用的变量在父组件内部。这种方式还可以隔代传递,即父组件将{el => this.inputElement = el}传递给子组件,再由子组件传递给孙组件使用。

注意:

Legacy API: String Refs

在以往的React中使用ref时,用的是字符串形式,比如:

<input ref='textInp'>

在组件内部可以使用this.refs.textInp获取对元素的引用(这是我在阮一峰先生几年前的博客中看到的)。

但是现在React不再推荐这种用法,并言明在以后的某个版本中将会取缔这种使用方式,说是有着某些问题。some issues

另外,ref的回调作为行内的function时,在渲染时可能会触发两次,第一次是旧组件销毁,传入null作为参数;第二次是新组件生成,同时也生成新的ref,传入组件本身作为参数。我们可以把ref回调作为class的内部方法绑定之。这样一来,ref回调不并重新建立,因为每次都是引用class内部的方法。

React:Refs and DOM的更多相关文章

  1. React文档(十六)refs和DOM

    Refs 提供了一种方式,用于访问在 render 方法中创建的 DOM 节点或 React 元素. 在标准的React数据流中,props是使得父组件和子组件之间交互的唯一方式.你通过props重新 ...

  2. React从入门到精通系列之(14)refs和DOM元素

    react.js 3.7k 次阅读  ·  读完需要 8 分钟 8 十四.refs和DOM元素 在典型的React数据流中,props是父组件与其子组件交互的唯一方式. 要修改子组件,需要使用一个新的 ...

  3. Refs 和 DOM

    在常规的 React 数据流中,props 是父组件与子组件交互的唯一方式.要修改子元素,你需要用新的 props 去重新渲染子元素.然而,在少数情况下,你需要在常规数据流外强制修改子元素.被修改的子 ...

  4. <读书笔记>《React:引领未来的用户界面开发框架》

    <React:引领未来的用户界面开发框架>(GitHub 附demo版) 1.Component的创建与复合 1.1 React简介 背景介绍,全书概览 1.本质上是一个状态机,它以精简的 ...

  5. [react] 什么是虚拟dom?虚拟dom比操作原生dom要快吗?虚拟dom是如何转变成真实dom并渲染到页面的?

    壹 ❀ 引 虚拟DOM(Virtual DOM)在前端领域也算是老生常谈的话题了,若你了解过vue或者react一定避不开这个话题,因此虚拟DOM也算是面试中常问的一个点,那么通过本文,你将了解到如下 ...

  6. [译] Angular 2 VS. React: 血色将至

    Angular 2 VS. React: 血色将至 原文链接:https://medium.com/@housecor/angular-2-versus-react-there-will-be-blo ...

  7. vue中使用refs定位dom出现undefined?

    之前在公司做项目,一直感觉用ref来定位dom节点挺方便的.但是期间遇到了一个问题,就是在mounted(){}钩子里面使用this.$refs.xxx,打印出来的却是undefined? 于是我就对 ...

  8. 深入理解react中的虚拟DOM、diff算法

    文章结构: React中的虚拟DOM是什么? 虚拟DOM的简单实现(diff算法) 虚拟DOM的内部工作原理 React中的虚拟DOM与Vue中的虚拟DOM比较 React中的虚拟DOM是什么?   ...

  9. 简谈react中的虚拟DOM

    相信你在看到此篇前也翻阅大量的对DOM的文章讲解和介绍 react中的虚拟DOM 此篇我尽量说人话(大白话),不然想必你在看到别的大神的文章早就懂了. 不说废话了,上干货. 1.首先简单对Html中的 ...

随机推荐

  1. 今天,VS Code 五岁了。

    时光飞逝,岁月如梭.今天,VS Code 迎来了 5 岁的生日. 回想起 VS Code 发布的那一天,仿佛还在昨天. 回顾 VS Code 这五年的发展,总是能给我们开发者带了无限的惊喜. 2015 ...

  2. 9、flink的状态与容错

    1.理解State(状态) 1.1.State 对象的状态 Flink中的状态:一般指一个具体的task/operator某时刻在内存中的状态(例如某属性的值) 注意:State和Checkpoint ...

  3. Android-网页解析-gson的使用

    相对于较为传统的Json解析来说,google共享的开源Gson在解析速度和所使用的内存在有着明显的优势,虽然说阿里巴巴也提供了fastgson包,但是它跟Gson的处理速度大同小异,只是底层实现的原 ...

  4. 3.k均值的算法

    一.课堂练习 # 课堂练习 from sklearn.datasets import load_iris # 导入鸢尾花数据 iris=load_iris() iris iris.keys() dat ...

  5. markdownPad常用功能示例

    1.列表 无序列表 姓名 张三 李四 王五 有序列表 张三 李四 王五 2.超链接 百度 3.引用 锄禾日当午,汗滴禾下土.谁知盘中餐,粒粒皆辛苦. -- 李绅<古风二首> 4.简要修饰文 ...

  6. Ubuntu 设置 log 级别

    Linux环境下使用rsyslog管理日志 rsyslog linux运维 linux 22.7k 次阅读  ·  读完需要 22 分钟     在 Linux 系统中,日志文件记录了系统中包括内核. ...

  7. js特效:鼠标滑过图片时切换为动图

    效果展示 事前准备 一张普通的静态图+与其对应的gif图. 实现思路 获取图片的src,改变其后缀,使其变成与之对应的gif图片.(很简单有木有= =) 具体实现 编写html代码 <div c ...

  8. Microsoft Dynamics CRM 2015 服务器系统的性能维护,追踪, 也可以用到任务管理器哟...

    Microsoft Dynamics CRM 2015 的追踪是一个很有用的function,它能为我们的CRM调试,评估 提供有价值的信息:我们可以用window的性能监控工具来了解CRM的性能状态 ...

  9. chrome清除缓存、不使用缓存而刷新快捷键

    Ctrl+Shift+Del  清除Google浏览器缓存的快捷键 Ctrl+Shift+R  重新加载当前网页而不使用缓存内容 转载于:https://www.cnblogs.com/JAVA-ST ...

  10. 可运行的Java RMI示例和踩坑总结

    简述 资料参考: https://docs.oracle.com/javase/tutorial/rmi/overview.html https://blog.csdn.net/bigtree_372 ...