React 受控和非受控组件

发布时间 2023-11-29 17:27:57作者: 背包の技术

无论你做什么,都要相信自己可以做到,因为你的潜力是无限的。

把父组件的状态变成属性传递给子组件,子组件接受这个属性,听命于父组件。这个子组件就是叫做受控组件。在受控与非受控组件有两种理解方案,第一:狭义上的受控与非受控,就是我们在表单中的受控与非受控组件。第二:广义上的受控与非受控组件,就是 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 则不然。