本文最后更新于:2020年12月30日 凌晨
场景 这些天在学习 React
的时候遇到了一个奇怪的问题,明明受控表单的双向绑定已经成功了,然而控制台还是会出现 react 的警告:
1 Warning: A component is changing an uncontrolled input of type undefined to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
代码很简单,仅仅只是一个登录表单
1 2 3 4 5 6 7 8 9 export class User { constructor ({ username, password } = {} ) { this .username = username this .password = password } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import React , { Component } from 'react' import { User } from './User' class App extends Component { constructor (props ) { super (props) this .state = { user : new User (), } } change = (e ) => { const el = e.target const k = el.name const v = el.value const user = { ...this .state .user } user[k] = v this .setState ({ user, }) } submit = () => {} reset = () => { this .setState ({ user : new User (), }) } render ( ) { const { username, password } = this .state .user return ( <div > <div > <label htmlFor ="username" > 用户名: </label > <input name ="username" value ={username} onChange ={this.change} /> </div > <div > <label htmlFor ="password" > 密码: </label > <input name ="password" value ={password} onChange ={this.change} /> </div > <div > <button onClick ={this.submit} > 登录</button > <button onClick ={this.reset} > 重置</button > </div > </div > ) } }export default App
在 App 组件的 constructor
中明明已经通过 new User()
初始化了 user
属性,然而在输入的时候,还是会出现警告。
注:此时在输入框中输入值,确实会影响到 react state 中的 user 属性,反之亦然。只有一点,当重置表单,即使用 this.setState({user: new User()})
重置 user 对象无法影响到页面上输入框的值。
此处出现了两个问题
为什么在输入的时候会出现警告
为什么重置之后输入框的值没有变化
解决 最终,吾辈在 StackOverflow 上找到了答案。 很重要的一句话:对于要控制的输入,其值必须与状态变量的值相对应。 最初并未满足这个条件,值为 null
的 state
属性会被 react
视为未定义,导致表单最初是不受控制的。但是,当 onChange
第一次被触发的时候,this.state.user.username
就被设置了。此时,满足了条件,从非受控表单转换为了受控表单并导致了控制台的警告。 同理,当使用 this.setState({user: new User()})
重置的时候,又变成了非受控表单,所以这里的绑定再次失效了。
注: react 使用 ==
而非 ===
比较是否为 null
,而 null == undefined
的值为 true
,所以。。。
那么,知道问题了之后,我们只要保证初始值 val != null
即可。 例如上面的代码可以修改 User.js
:
1 2 3 4 5 6 7 8 9 export class User { constructor ({ username = '' , password = '' } = {} ) { this .username = username this .password = password } }
那么,关于 react 中的受控表单初始化的问题便到此为止了。可想而知,react 的坑还有很多没有踩完呢