React MUI TextField选值时报非受控输入转受控警告问题
使用React结合MUI组件库开发时,选择TextField下拉选项的过程中,控制台会抛出如下警告:
Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
最小可复现代码如下:
import React, {useState} from "react"; import MenuItem from "@mui/material/MenuItem"; import TextField from "@mui/material/TextField"; export default function Inputs() { //const [gender, setGender] = useState(""); return ( <TextField select //onChange={e => setGender(e.target?.value)} > <MenuItem key={"a"} value={"a"}>a</MenuItem> </TextField> ); }
React的表单组件分为两种运行模式,两种模式不能在组件生命周期内随意切换:
- 受控模式:组件绑定
value属性,值完全由React状态接管控制 - 非受控模式:组件不绑定
value属性,值由DOM自身维护,仅可通过defaultValue设置初始值
上述复现代码中,TextField初始渲染时没有传入value属性,MUI内部会将其识别为非受控组件,此时内部值为undefined;当用户点击选择下拉选项时,MUI会将选中项的值传入组件作为value,组件瞬间从非受控模式切换为受控模式,直接触发React的规则校验警告。
两种修复方式二选一即可,核心原则是保证组件从挂载到卸载的全生命周期内,始终保持同一种模式:
方式1:使用受控组件(业务开发最常用)
显式绑定状态与组件的value、onChange属性,给状态设置非undefined的初始值,放开复现代码中被注释的逻辑即可:
import React, {useState} from "react"; import MenuItem from "@mui/material/MenuItem"; import TextField from "@mui/material/TextField"; export default function Inputs() { // 初始值设为空字符串,保证value始终是有定义的字符串类型 const [gender, setGender] = useState(""); return ( <TextField select value={gender} onChange={e => setGender(e.target.value)} > <MenuItem key={"a"} value={"a"}>a</MenuItem> </TextField> ); }
方式2:使用非受控组件
如果不需要通过代码实时控制选中值,可直接给组件传入defaultValue设置初始值,不绑定value属性:
import React from "react"; import MenuItem from "@mui/material/MenuItem"; import TextField from "@mui/material/TextField"; export default function Inputs() { return ( <TextField select defaultValue="" > <MenuItem key={"a"} value={"a"}>a</MenuItem> </TextField> ); }
内容的提问来源于stack exchange,提问作者Sebastian Nielsen

