- A+
无论你做什么,都要相信自己可以做到,因为你的潜力是无限的。
把父组件的状态变成属性传递给子组件,子组件接受这个属性,听命于父组件。这个子组件就是叫做受控组件。在受控与非受控组件有两种理解方案,第一:狭义上的受控与非受控,就是我们在表单中的受控与非受控组件。第二:广义上的受控与非受控组件,就是 React 组件的数据渲染是通过父组件传递过来的属性控制的,能完全控制得住的就是受控组件,不能完全控制住的就是非受控组件。
1. 表单中非受控组件
React 要编写一个表单非受控组件,可以使用 ref 来从 DOM 节点中获取表单数据(访问节点,通过节点访问值),与状态没有任何关系,这种就是非受控组件。 下面代码使用非受控组件接受一个表单的值:
import React, { Component } from 'react' export default class App extends Component { myusername = React.createRef() render() { return ( <div> <h4>登录页</h4> {/* 这里设置 value 后导致 input 不能输入了。写成 value 形式本身就是一种受控方式。被字符串 “hubert” 控制住了。*/} <input type={"text"} ref={this.myusername} value="hubert"></input> {/* 非受控需要通过 defaultValue 设置默认值,只是第一次设置值 */} <input type={"text"} ref={this.myusername} defaultValue="hubert"></input> <button onClick={()=>{ console.log(this.myusername.current.value) }}>登录</button> <button onClick={()=>{ this.myusername.current.value = "" }}>重置</button> </div> ) } }
因为非受控组件将真实数据储存在 DOM 节点中,所以在使用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码美观性,并且希望快速编写代码,使用非受控组件往往可以减少你的代码量。否则,你应该使用受控组件。
默认值问题:在React 渲染生命周期时,表单元素上的 value 将会覆盖 DOM 节点中的值,在非受控组件中,你经常希望 React 能赋予组件一个初始值,但是不去控制后续的更新。在这种情况下,你可以指定一个 defaultvalue 属性,而不是 value。
2. 表单中受控组件
现在如果有一个子组件需要拿到表单中的 value 值,该怎么办?这里在输入框值变更的时候,是不会同步、分享到子组件的,因为 render 函数是不会重新执行的。
在 HTML 中,表单元素(如 <input>
和 <select>
)通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState() 来更新。我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做"受控组件”。
{/* 在输入框值变更的时候,是不会同步、分享到子组件的 */} <Child value={this.myusername.current.value}></Child> // 设置成受控组件后后 <Child value={this.state.username}></Child>
import React, { Component } from 'react' export default class App extends Component { state = { username: "hubert" } render() { return ( <div> <h4>登录页</h4> {/* 这里设置 value 后导致 input 不能输入了。写成 value 形式本身就是一种受控方式。被字符串 “hubert” 控制住了。*/} {/* 非受控需要通过 defaultValue 设置默认值,只是第一次设置值 */} <input type={"text"} ref={this.myusername} value={this.state.username} onChange={(evt)=>{ this.setState({ username: evt.target.value }) }}></input> <button onClick={()=>{ console.log(this.state.username) }}>登录</button> <button onClick={()=>{ this.setState({ username:"" }) }}>重置</button> {/* 在输入框值变更的时候,是不会同步、分享到子组件的 */} {/* <Child value={this.myusername.current.value}></Child> */} </div> ) } } // 在 react 中 onInput 和 onChange 事件的行为一样的。原生 JS 则不然。