refs 的使用
在 React 的开发模式中, 通常情况下不需要、也不建议直接操作 DOM 元素, 但是某些特殊的情况, 确实需要获取到 DOM 进行某些操作, 例如
- 管理焦点、文本选择、媒体播放等
- 触发强制动画
- 集成第三方 DOM 库
创建 ref 的方式
如何创建 refs 来获取对应的 DOM 呢? 目前有三种方式
- 传入字符串
- 使用时通过
this.refs.传入的字符串
格式获取对应的元素
- 使用时通过
- 传入对象
- 对象通过
React.createRef()
方式创建 - 使用时获取到创建的对象其中有一个
current
属性就是对应的元素
- 对象通过
- 传入函数
- 该函数会在 DOM 被挂载时进行回调, 这个函数会传入一个元素对象, 我们可以自己保存
- 使用时, 直接拿到之前报错的元素对象即可
1 | import React, { PureComponent, createRef } from 'react' |
ref 节点的类型
ref
的值根据节点的类型而有所不同
- 当
ref
属性用于 HTML 元素时, 构造函数中使用React.createRef()
创建的ref
接收底层 DOM 元素作为其current
属性 - 当
ref
属性用于自定义 Class 组件时,ref
对象接收组件的挂载实例作为其current
属性 - 你不能在函数组件上使用
ref
属性, 因为它们没有实例
1 | import React, { PureComponent, createRef } from 'react' |
上面的代码中, 在App
组件中ref
属性用于Counter
组件上, 所以ref
对象的current
属性为Counter
组件实例, 从而可以通过App
组件调用Counter
组件的increment
方法
函数式组件没有实例, 所以无法通过
ref
获取它们的实例
- 但是某些时候, 我们可能想要获取函数式组件中的某个 DOM 元素
- 这个时候我们可以通过
React.forwardRef
受控组件
认识受控组件
默认提交表单方式
在React
中, HTML 表单的处理方式和普通的 DOM 元素不太一样, 表单元素通常会保存一些内部的state
比如下面的 HTML 表单元素
1 | <form> |
- 这个处理方式是 DOM 默认处理 HTML 表单的行为, 在用户点击提交时会提交到某个服务器上, 并且刷新页面
- 在 React 中, 并没有禁止这个行为, 它依然是有效的
- 但是通常情况下会使用 JavaScript 函数来方便的处理表单提交, 同时还可以访问用户填写的表单数据
- 实现这种效果的标准方式是使用“受控组件”
受控组件提交表单
在 HTML 中, 表单元素(如<input>
、<textarea>
和<select>
)通常自己维护state
, 并根据用户输入进行更新
而在 React 中, 可变状态(mutable state)通常保存在组件的state
属性中, 并且只能通过使用setState()
来更新
- 将两者结合起来, 使
React
的state
成为“唯一数据源” - 渲染表单的 React 组件还控制着用户输入过程中表单发生的操作
- 被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”
例如, 如果我们想让前一个示例在提交时打印出用户名, 那么就可以将表单改写为受控组件
1 | import React, { PureComponent } from 'react' |
由于在表单元素上设置了value
属性, 因此显示的值将始终为this.state.username
, 这使得 React 的state
成为唯一数据源
由于handleUsernameChange
在每次输入时都会执行并更行 React 的state
, 因此显示的值将随着用户输入而更新
常见表单的处理
Element | Value property | Change callback | New value in the callback |
---|---|---|---|
<input type="text" /> | value="string" | onChange | event.target.value |
<input type="checkbox" /> | checked={boolean} | onChange | event.target.checked |
<input type="radio" /> | value="string" | onChange | event.target.checked |
<textarea /> | value="string" | onChange | event.target.value |
<select /> | value="option value" | onChange | event.target.value |
textarea 标签
textarea
标签和input
比较相似
1 | import React, { PureComponent } from 'react' |
select 标签
select
标签的使用也非常简单, 只是它不需要通过selected
属性来控制哪一个被选中, 它可以匹配state
的value
来选中
1 | import React, { PureComponent } from 'react' |
处理多个输入
多处理方式可以像单处理方式那样进行操作, 但是需要多个监听方法
- 这里我们可以使用 ES6 的一个语法: 计算属性名(Computed property names)
1 | let i = 0 |
对应的代码示例如下
1 | import React, { PureComponent } from 'react' |
非受控组件
React 推荐大多数情况下使用受控组件来处理表单数据
- 一个受控组件中, 表单数据是由 React 组件来管理的
- 另一种替代方案是使用非受控组件, 这时表单数据将交由 DOM 节点来处理
如果要使用非受控组件中的数据, 那么我们需要使用ref
来从 DOM 节点中获取表单数据
1 | import React, { PureComponent, createRef } from 'react' |
- 使用
ref
来获取input
元素 - 在非受控组件中通常使用
defaultValue
来设置默认值
同样, <input type="checkbox" />
和<input type="radio" />
支持defaultChecked
, <select />
和<textarea />
支持defaultValue