"小和山的菜鸟们",为前端开发者提供技术相关资讯以及系列基础文章。为更好的用户体验,请您移至咱们官网小和山的菜鸟们 ( xhs-rookies.com/ ) 进行学习,及时获取最新文章。html
"Code tailor" ,若是您对咱们文章感兴趣、或是想提一些建议,微信关注 “小和山的菜鸟们” 公众号,与咱们取的联系,您也能够在微信上观看咱们的文章。每个建议或是赞同都是对咱们极大的鼓励!前端
这节咱们将介绍 React
中受控组件和非受控组件的概念及其使用。react
本文会向你介绍如下内容:web
在 HTML
中,表单元素如 <input>
,<textarea>
和 <select>
表单元素一般保持本身的状态,并根据用户输入进行更新。而在 React
中,可变状态通常保存在组件的 state(状态)
属性中,而且只能经过 setState()
更新。数组
咱们能够经过使 React
的 state
成为 “单一数据源原则” 来结合这两个形式。而后渲染表单的 React 组件也能够控制在用户输入以后的行为。浏览器
这种形式,其值由 React
控制的输入表单元素称为“受控组件”。微信
那么相反的,值并不禁 React
进行控制,该组件本身输入,减小等等,该元素成为非受控组件。markdown
关于何时使用受控组件,何时使用非受控组件,能够查看这一篇文章:app
HTML
表单元素与 React
中的其余 DOM
元素有所不一样,由于表单元素天然地保留了一些内部状态。
例如,这个纯 HTML
表单接受一个单独的 name
:
<form>
<label> 名字: <input type="text" name="name" /> </label>
<input type="submit" value="提交" />
</form>
复制代码
该表单和 HTML
表单的默认行为一致,当用户提交此表单时浏览器会打开一个新页面。若是你但愿 React
中保持这个行为,也能够工做。
可是多数状况下,咱们会让 React
组件来管理这些数据,并在点击提交这些数据并触发打开新页面的操做。
这就用到了“受控组件(controlled components
)”。
在 HTML
中,表单元素(如<input>
、 <textarea>
和 <select>
)之类的表单元素一般本身维护 state,并根据用户输入进行更新。
而在 React
中,可变状态(mutable state
)一般保存在组件的 state 属性中,而且只能经过使用 setState()
来更新。
React
的 state
成为“惟一数据源”;React
组件还控制着用户输入过程当中表单发生的操做;React
以这种方式控制取值的表单输入元素就叫作“受控组件”;例如,若是咱们想让前一个示例在提交时打印出名称,咱们能够将表单写为受控组件:
class App extends PureComponent {
constructor(props) {
super(props)
this.state = {
username: '',
}
}
render() {
const { username } = this.state
return (
<div> <form onSubmit={(e) => this.handleSubmit(e)}> <label htmlFor="username"> 用户名: <input type="text" id="username" onChange={(e) => this.handleUsernameChange(e)} value={username} /> </label> <input type="submit" value="提交" /> </form> </div>
)
}
handleUsernameChange(event) {
this.setState({
username: event.target.value,
})
}
handleSubmit(event) {
console.log(this.state.username)
event.preventDefault()
}
}
复制代码
因为在表单元素上设置了 value
属性,所以显示的值将始终为 this.state.value
,这使得 React 的 state 成为惟一数据源。
因为 handleUsernameChange
在每次按键时都会执行并更新 React
的 state
,所以显示的值将随着用户输入而更新。
在 React
的开发模式中,一般状况下不须要、也不建议直接操做 DOM
原生,可是某些特殊的状况,确实须要获取到 DOM
进行某些操做:
DOM
库。咱们这里若是使用非受控组件就会有一个问题,如何获取该组件的数据,这里就能够用 Refs
来获取该组件,而后就能够获取到该组件的数据了。所以咱们先简述 Refs
的内容。
**注意:**固然还有其余的方法能够获取组件内容,例如:变量提高到父组件统一管理、事件监听。
如何建立 refs
来获取对应的 DOM
呢?目前有三种方式:
使用时经过 this.refs.传入的字符串
格式获取对应的元素;
对象是经过 React.createRef()
方式建立出来的;使用时获取到建立的对象其中有一个current
属性就是对应的元素;
该函数会在 DOM
被挂载时进行回调,这个函数会传入一个 元素对象,咱们能够本身保存;使用时,直接拿到以前保存的元素对象便可;
代码演练:
class App extends PureComponent {
constructor(props) {
super(props)
this.titleRef = createRef()
this.titleEl = null
}
render() {
return (
<div> <h2 ref="title">String Ref</h2> <h2 ref={this.titleRef}>Hello Create Ref</h2> <h2 ref={(element) => (this.titleEl = element)}>Callback Ref</h2> <button onClick={(e) => this.changeText()}>改变文本</button> </div>
)
}
changeText() {
this.refs.title.innerHTML = '你好啊,小和山的菜鸟们'
this.titleRef.current.innerHTML = '你好啊,小和山的菜鸟们'
this.titleEl.innerHTML = '你好啊,小和山的菜鸟们'
}
}
复制代码
ref
的值根据节点的类型而有所不一样:
ref
属性用于 HTML
元素时,构造函数中使用 React.createRef()
建立的 ref
接收底层 DOM
元素做为其 current
属性;ref
属性用于自定义 class
组件时,ref
对象接收组件的挂载实例做为其 current
属性;ref
属性,由于他们没有实例;这里咱们演示一下 ref
引用一个 class
组件对象:
class Counter extends PureComponent {
constructor(props) {
super(props)
this.state = {
counter: 0,
}
}
render() {
return (
<div> <h2>当前计数: {this.state.counter}</h2> <button onClick={(e) => this.increment()}>+1</button> </div>
)
}
increment() {
this.setState({
counter: this.state.counter + 1,
})
}
}
class App extends PureComponent {
constructor(props) {
super(props)
this.counterRef = createRef()
}
render() {
return (
<div> <Counter ref={this.counterRef} /> <button onClick={(e) => this.increment()}>app +1</button> </div>
)
}
increment() {
this.counterRef.current.increment()
}
}
复制代码
函数式组件是没有实例的,因此没法经过 ref
获取他们的实例,可是某些时候,咱们可能想要获取函数式组件中的某个 DOM
元素,这个时候咱们能够经过 React.forwardRef
,后面咱们也会学习 hooks
中如何使用 ref
。
React
推荐大多数状况下使用受控组件来处理表单数据:
React
组件来管理的;DOM
节点来处理;若是要使用非受控组件中的数据,那么咱们须要使用 Ref
来从 DOM
节点中获取表单数据。
咱们来进行一个简单的演练:
ref
来获取 input
元素;defaultValue
来设置默认值;class App extends PureComponent {
constructor(props) {
super(props)
this.usernameRef = createRef()
}
render() {
return (
<div> <form onSubmit={(e) => this.handleSubmit(e)}> <label htmlFor=""> 用户: <input defaultValue="username" type="text" name="username" ref={this.usernameRef} /> </label> <input type="submit" value="提交" /> </form> </div>
)
}
handleSubmit(event) {
event.preventDefault()
console.log(this.usernameRef.current.value)
}
}
复制代码
一样,<input type="checkbox">
和 <input type="radio">
支持 defaultChecked
,<select>
和 <textarea>
支持 defaultValue
。
本节咱们学习了 React
中控组件和非受控组件的内容,在下一个章节咱们将继续学习 React
中高阶组件以及组件补充的内容,敬请期待!