React 受控和非受控组件

  • React 受控和非受控组件已关闭评论
  • 74 次浏览
  • A+
所属分类:Web前端
摘要

无论你做什么,都要相信自己可以做到,因为你的潜力是无限的。把父组件的状态变成属性传递给子组件,子组件接受这个属性,听命于父组件。这个子组件就是叫做受控组件。在受控与非受控组件有两种理解方案,第一:狭义上的受控与非受控,就是我们在表单中的受控与非受控组件。第二:广义上的受控与非受控组件,就是 React 组件的数据渲染是通过父组件传递过来的属性控制的,能完全控制得住的就是受控组件,不能完全控制住的就是非受控组件。


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

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