组件正在更改ReactJS中要控制的文本类型的不受控制的输入错误

警告:组件正在更改要控制的文本类型的不受控制的输入。输入元素不应从不受控制切换到受控制(反之亦然)。在组件的生命周期内决定使用受控或不受控制的输入元素。*

以下是我的代码:

constructor(props) {super(props);this.state = {fields: {},errors: {}}this.onSubmit = this.onSubmit.bind(this);}
....
onChange(field, e){let fields = this.state.fields;fields[field] = e.target.value;this.setState({fields});}
....
render() {return(<div className="form-group"><inputvalue={this.state.fields["name"]}onChange={this.onChange.bind(this, "name")}className="form-control"type="text"refs="name"placeholder="Name *"/><span style={{color: "red"}}>{this.state.errors["name"]}</span></div>)}
568642 次浏览

原因是,在你定义的状态中:

this.state = { fields: {} }

字段作为空白对象,因此在第一次渲染期间this.state.fields.name将是undefined,输入字段的值将为:

value={undefined}

因此,输入字段将变得不受控制。

一旦你在输入中输入任何值,状态中的fields就会更改为:

this.state = { fields: {name: 'xyz'} }

此时,输入字段被转换为受控组件;这就是为什么你会得到错误:

组件正在将文本类型的不受控制的输入更改为控制。

可能的解决方案:

1-将状态中的fields定义为:

this.state = { fields: {name: ''} }

2-或者使用短路评估定义value属性,如下所示:

value={this.state.fields.name || ''}   // (undefined || '') = ''

首先设置当前状态...this.state

这是因为当你要分配一个新的状态时,它可能是未定义的,所以它将通过设置状态提取当前状态来修复

this.setState({...this.state, field})

如果你的状态中有一个对象,你应该按如下方式设置状态,假设您必须在user对象中设置username。

this.setState({user:{...this.state.user, ['username']: username}})

简单,您必须先设置初始状态

如果你不设置初始状态反应会把它当作不受控分量

value更改为defaultValue将解决此问题。

说明

defaultValue仅用于初始负载。如果你想初始化input,那么你应该使用defaultValue,但是如果你想使用state来更改值,那么你需要使用value。阅读这个了解更多。

我在input中使用了value={this.state.input ||""}来摆脱这个警告。

在组件内部按以下方式放置输入框。

<input className="class-name"type= "text"id="id-123"value={ this.state.value || "" }name="field-name"placeholder="Enter Name"/>
const [name, setName] = useState()

在文本字段中键入后立即生成错误

const [name, setName] = useState('') // <-- by putting in quotes

将修复此字符串示例中的问题。

除了接受的答案之外,如果您使用的是checkboxradio类型的input,我发现我还需要检查checked属性的null/未定义。

<inputid={myId}name={myName}type="checkbox" // or "radio"value={myStateValue || ''}checked={someBoolean ? someBoolean : false}/>

如果你使用的是TS(或Babel),你可以使用空合并而不是逻辑OR运算符:

value={myStateValue ?? ''}checked={someBoolean ?? false}

在我的情况下,这几乎是Mayank Shukla的最高答案所说的。唯一的细节是,我的州完全缺乏我所定义的财产。

例如,如果您有以下状态:

state = {"a" : "A","b" : "B",}

如果你正在扩展你的代码,你可能想要添加一个新的prop,所以,在你的代码中的其他地方,你可能会创建一个新的属性c,它的值不仅在组件的状态上是未定义的,而且属性本身也是未定义的。

要解决这个问题,请确保将c添加到您的状态并为其提供适当的初始值。

例如,

state = {"a" : "A","b" : "B","c" : "C", // added and initialized property!}

希望我能解释一下我的边缘案例。

如果在on字段中使用多个输入,请遵循:例如:

class AddUser extends React.Component {constructor(props){super(props);
this.state = {fields: { UserName: '', Password: '' }};}
onChangeField = event => {let name = event.target.name;let value = event.target.value;this.setState(prevState => {prevState.fields[name] =  value;return {fields: prevState.fields};});};
render() {const { UserName, Password } = this.state.fields;return (<form><div><label htmlFor="UserName">UserName</label><input type="text"id='UserName'name='UserName'value={UserName}onChange={this.onChangeField}/></div><div><label htmlFor="Password">Password</label><input type="password"id='Password'name='Password'value={Password}onChange={this.onChangeField}/></div></form>);}}

搜索您的问题:

onChangeField = event => {let name = event.target.name;let value = event.target.value;this.setState(prevState => {prevState.fields[name] =  value;return {fields: prevState.fields};});};

警告:组件正在更改要控制的文本类型的不受控制的输入。输入元素不应从不受控制切换到受控(反之亦然)。在组件的生命周期内决定使用受控或不受控制的输入元素。

解决方案:检查value是否未定义

React/Formik/Bootstrap/TypeScript

例子:

{ values?.purchaseObligation.remainingYear ?<Inputtag={Field}name="purchaseObligation.remainingYear"type="text"component="input"/> : null}

使用ReactHooks也不要忘记设置初始值。
我使用的是<input type='datetime-local' value={eventStart} />,初始eventStart就像

const [eventStart, setEventStart] = useState();
改为
const [eventStart, setEventStart] = useState('');.

括号中的空字符串是差异。
此外,如果您像我一样在提交后重置表单,再次需要将其设置为空字符串,而不仅仅是空括号。

这只是我对这个话题的小小贡献,也许会对某人有所帮助。

可以应用多种方法:

  • 基于类的方法:使用本地状态并使用默认值定义现有字段:
constructor(props) {super(props);this.state = {value:''}}<input type='text'name='firstName'value={this.state.value}className="col-12"onChange={this.onChange}placeholder='Enter First name' />
  • 在函数式样式组件中使用Hooks React>16.8:
[value, setValue] = useState('');<input type='text'name='firstName'value={value}className="col-12"onChange={this.onChange}placeholder='Enter First name' />
  • 如果在函数式风格的HOC组件的情况下使用proTypes并为proTypes提供默认值。
 HOC.propTypes = {value       : PropTypes.string}HOC.efaultProps = {value: ''}
function HOC (){
return (<input type='text'name='firstName'value={this.props.value}className="col-12"onChange={this.onChange}placeholder='Enter First name' />)
}

如果值不存在或为null,则放空值。

value={ this.state.value || "" }

当输入字段值未定义时,此问题的原因是抛出反应的警告。如果您为多个输入字段创建一个ChangeHandler,并且您想使用ChangeHandler更改状态,那么您需要使用扩展运算符分配以前的值。就像我这里的代码一样。

constructor(props){super(props)this.state = {user:{email:'',password:''}}}
// This handler work for every input fieldchangeHandler = event=>{// Dynamically Update State when change input valuethis.setState({user:{...this.state.user,[event.target.name]:event.target.value}})}
submitHandler = event=>{event.preventDefault()
// Your Code Here...}
render(){return (<div className="mt-5">       
<form onSubmit={this.submitHandler}><input type="text" value={this.state.user.email} name="email" onChage={this.changeHandler} />                
<input type="password" value={this.state.user.password} name="password" onChage={this.changeHandler} />
<button type="submit">Login</button></form>      

</div>)}

改变这个

  const [values, setValues] = useState({intialStateValues});

为此

  const [values, setValues] = useState(intialStateValues);

像这样

value={this.state.fields && this.state.fields["name"] || ''}

为我工作。

但是我设置了这样的初始状态:

this.state = {fields: [],}

我用反应钩子遇到了同样的警告虽然我之前已经初始化了初始状态:-

const [post,setPost] = useState({title:"",body:""})

但后来我覆盖了onChange事件处理程序上预定义状态对象的一部分,

 const onChange=(e)=>{setPost({[e.target.name]:e.target.value})}

解决方案我通过首先处理前一个状态的整个对象(通过使用传播运算符)然后在其上进行编辑来解决这个问题,

 const onChange=(e)=>{setPost({...post,[e.target.name]:e.target.value})}

如上所述,您需要设置初始状态,在我的情况下,我忘记在setSate()中添加''引号;

  const AddUser = (props) => {const [enteredUsername, setEnteredUsername] = useState()const [enteredAge, setEnteredAge] = useState()

给出以下错误

在此处输入图片描述

正确的代码是简单地将初始状态设置为空字符串''

  const AddUser = (props) => {const [enteredUsername, setEnteredUsername] = useState('')const [enteredAge, setEnteredAge] = useState('')

解决此问题的最佳方法是将初始状态设置为''

constructor(props) {super(props)this.state = {fields: {first_name: ''}}this.onChange = this.onChange.bind(this);}
onChange(e) {this.setState({fields:{...this.state.fields,[e.target.name]: e.target.value}})}

render() {return(<div className="form-group"><inputvalue={this.state.fields.first_name}onChange={this.onChange}className="form-control"name="first_name" // Same as state keytype="text"refs="name"placeholder="Name *"/><span style=\{\{color: "red"}}>{this.state.errors.first_name}</span></div>)}

然后,您仍然可以像if (field)一样运行检查,如果您的值为'',则仍然可以获得相同的结果。

现在,由于您的值在评估后被归类为类型字符串而不是未定义。因此,从控制台清除一个大红色块的错误😁😎。

如果您将value属性设置为对象的属性,并且希望确保该属性不是untex,那么您可以将null合并运算符??与可选的链接运算符?.组合,如下所示:

<inputvalue={myObject?.property ?? ''}/>

我也遇到了同样的问题。我的解决方案是我错过了向元素添加'name'属性。

<div className="col-12"><label htmlFor="username" className="form-label">Username</label><div className="input-group has-validation"><span className="input-group-text">@</span><inputtype="text"className="form-control"id="username"placeholder="Username"required=""value={values.username}onChange={handleChange}/><div className="invalid-feedback">Your username is required.</div></div></div>

在输入属性列表中引入name=username后,它工作得很好。

对于功能组件:

const SignIn = () => {
const [formData, setFormData] = useState({email: "",password: ""});
  
const handleChange = (event) => {const { value, name } = event.target;setFormData({...formData, [name]: value });};

const handleSubmit = (e) => {e.preventDefault();console.log("Signed in");setFormData({email: "",password: ""});};

return (<div className="sign-in-container"><form onSubmit={handleSubmit}><FormInputname="email"type="email"value={formData.email}handleChange={handleChange}label="email"required/><FormInputname="password"type="password"value={formData.password}handleChange={handleChange}label="password"required/><CustomButton type="submit">Sign in</CustomButton></form></div>);};
export default SignIn;

虽然这听起来很疯狂,但对我来说解决这个问题的方法是添加一个额外的div。一部分代码作为示例:

  ... [Other code] ...const [brokerLink, setBrokerLink] = useState('');... [Other code] ...
return (... [Other code] ...<div styleName="advanced-form" style=\{\{ margin: '0 auto', }}>{/* NOTE: This div */}<div><div styleName="form-field"><div>Broker Link</div><inputtype="text"name="brokerLink"value={brokerLink}placeholder=""onChange={e => setBrokerLink(e.target.value)}/></div></div></div>... [Other code] ...);... [Other code] ...

很奇怪。没有这个额外的div,似乎出于某种原因,它最初呈现的输入元素没有值属性,而是空样式属性。你可以通过查看html看到这一点。这导致了控制台警告…

更奇怪的是,添加一个不是空字符串的默认值或做类似value={brokerLink || ''}的事情会导致完全相同的问题。

另一个奇怪的事情是,我有30个几乎完全相同的其他元素,但没有引起这个问题。唯一的区别是这个经纪链接没有那个外部div…并将其移动到代码的其他部分而不更改任何内容,出于某种原因删除了警告…

如果没有我的确切代码,可能几乎不可能复制。如果这不是bug或其他什么,我不知道是什么。

发生这种情况是因为值不能未定义或null来解决您可以这样做

value={ this.state.value ?? "" }

我是reactjs新手,我正在使用reactjs的第17版我遇到了这个问题

我解决了:

而不是这个

const [email, setEmail] = useState();

我加了这个

const [email, setEmail] = useState("");

在useState函数中,我添加了引号来初始化数据,错误消失了。

对我来说,这是一个错误:

<input onChange={onClickUpdateAnswer} value={answer.text}>{answer.text}</input>

如您所见,我将字符串传递到Input标记的主体中,

修复:

<input onChange={onClickUpdateAnswer} value={answer.text}></input>

即使您在正确初始化事物之前将未定义设置为先前呈现时的值,也会出现问题。

问题是取代

value={value}

value={(value==undefined?null:value)}