반응-제어되지 않은 입력 변경


359

제어 된 입력이 하나 있다고 생각되는 형식의 간단한 반응 구성 요소가 있습니다.

import React from 'react';

export default class MyForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {}
    }

    render() {
        return (
            <form className="add-support-staff-form">
                <input name="name" type="text" value={this.state.name} onChange={this.onFieldChange('name').bind(this)}/>
            </form>
        )
    }

    onFieldChange(fieldName) {
        return function (event) {
            this.setState({[fieldName]: event.target.value});
        }
    }
}

export default MyForm;

내 응용 프로그램을 실행하면 다음 경고가 나타납니다.

경고 : MyForm이 제어 할 텍스트 유형의 제어되지 않은 입력을 변경하고 있습니다. 입력 요소는 제어되지 않은 상태에서 제어 된 상태로 또는 그 반대로 전환해서는 안됩니다. 구성 요소의 수명 동안 제어 또는 제어되지 않은 입력 요소 사용 여부 결정

나는 가치가 있기 때문에 입력이 통제된다고 생각합니다. 내가 뭘 잘못하고 있는지 궁금해?

React 15.1.0을 사용하고 있습니다

답변:


509

나는 가치가 있기 때문에 입력이 통제된다고 생각합니다.

입력을 제어하려면 해당 값이 상태 변수의 값과 일치해야합니다.

this.state.name처음에 설정되지 않았기 때문에 해당 조건이 예제에서 처음 충족 되지 않았습니다. 따라서 입력은 처음에는 제어되지 않습니다. 한 번 onChange핸들러가 처음으로 트리거, this.state.name설정됩니다. 이때 상기 조건이 만족되고 입력이 제어 된 것으로 간주된다. 제어되지 않은 상태에서 제어 된 상태로 전환하면 위에서 본 오류가 발생합니다.

this.state.name생성자에서 초기화 하여 :

예 :

this.state = { name: '' };

입력이 처음부터 제어되어 문제가 해결됩니다. 자세한 예는 반응 제어 구성 요소 를 참조하십시오 .

이 오류와 관련이없는 경우 기본 내보내기는 하나만 있어야합니다. 위의 코드에는 두 가지가 있습니다.


7
답변을 읽고 아이디어를 여러 번 따르는 것은 어렵지만이 답변은 시청자에게 동시에 이야기하고 이야기하는 완벽한 방법입니다. 답변 수준의 신!
surajnew55

2
루프에 동적 필드가 있으면 어떻게됩니까? 예를 들어 필드 이름을 name={'question_groups.${questionItem.id}'}?
user3574492

2
동적 필드의 작동 방식 양식을 동적으로 생성 한 다음 객체 내부 상태에서 필드 이름을 설정하고 있습니다. 먼저 필드 이름을 먼저 수동으로 설정 한 다음 내 객체로 전송해야합니까?
Joseph

13
이 답변은 약간 잘못되었습니다. prop에 null이 아닌 / 정의되지 않은 값이 있으면value 입력이 제어 됩니다 . 소품은 상태 변수에 해당 할 필요가 없습니다 (상수 일 수 있으며 구성 요소는 여전히 제어 된 것으로 간주됩니다). 아담의 대답이 더 정확하고 받아 들여 져야합니다.
ecraig12345 2018

2
예-이것은 기술적으로 잘못된 답변입니다 (그러나 도움이됩니다). 참고 사항-라디오 버튼 ( '값'이 약간 다르게 제어 됨)을 처리하는 경우 구성 요소가 (현재) 제어 되더라도 실제로 반응 반응 경고가 발생할 수 있습니다. github.com/facebook/react/issues/6779 이며 !! isChecked
진실의 진실성에

123

먼저 구성 요소를 렌더링 할 때, this.state.name이 평가되도록 설정되어 있지 않은 undefined또는 null, 당신은 통과 끝날 value={undefined}또는 value={null}당신을에 input.

필드가 제어되는 경우 ReactDOM 여부를 확인하는 경우 그것을 확인 있는지 확인하기 위해value != null (그것의주의 !=,하지를 !==)하고 있기 때문에 undefined == null자바 스크립트에서, 그것은 통제되지 않은하다고 결정한다.

따라서 onFieldChange()호출 될 때 this.state.name문자열 값으로 설정되면 입력이 제어되지 않는 상태에서 제어되는 상태가됩니다.

this.state = {name: ''}생성자에서 수행하는 경우 '' != null, 입력은 항상 값을 가지므로 해당 메시지는 사라집니다.


5
가치가있는 것에 대해서도 같은 일이 일어날 수 있습니다 this.props.<whatever>. 고마워, 아담!
Don

네! 에서 정의한 계산 된 변수 render()또는 태그 자체의 표현식 (평가 된 것)을 전달하는 경우에도 발생할 수 있습니다 undefined. 기꺼이 도와 드리겠습니다!
레이 Brenecki

1
이 답변에 감사드립니다. 승인 된 것은 아니지만 "지정"보다 문제를 훨씬 잘 설명합니다 name.
machineghost

1
제어 된 입력의 작동 방식을 설명하기 위해 답변을 업데이트했습니다. 여기서 중요한 것은 undefined초기에 값 이 전달되는 것이 아니라는 점에 주목할 가치가 있습니다. 오히려, this.state.name입력을 제어 할 수 없게 만드는 상태 변수로 존재하지 않는 것이 사실입니다 . 예를 들어, this.state = { name: undefined };입력이 제어 될 수 있습니다. 중요한 것은 가치가 아닌 가치가 어디에서 나오는지 이해해야합니다.
fvgs

1
@fvgs this.state = { name: undefined }는 여전히 제어되지 않은 입력을 초래합니다. <input value={this.state.name} />에 설탕을 제거합니다 React.createElement('input', {value: this.state.name}). 객체의 존재하지 않는 속성에 액세스하면 undefined이 반환 React.createElement('input', {value: undefined})되므로을 name설정하거나 명시 적으로 설정하지 않더라도 undefinedReact도 동일한 방식으로 작동합니다. 이 JSFiddle에서이 동작을 볼 수 있습니다.
레이 Brenecki

52

다른 접근 방식은 다음과 같이 입력 내부의 기본값을 설정하는 것입니다.

 <input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>

1
<input name = "name"type = "text"defaultValue = ""onChange = {this.onFieldChange ( 'name'). bind (this)} /> 이것도 효과가 있다고 생각합니다
gandalf

고마워요, 이것은 내가 찾던 것입니다. 이 패턴을 사용할 때 고려해야 할 단점이나 잠재적 인 문제가 있습니까?
Marcel

필드는 API에서 동적으로 렌더링되므로 구성 요소가 마운트 될 때 필드 이름을 알지 못하기 때문에 나에게 도움이되었습니다. 이것은 치료를했다!
Jamie-Fenrir Digital Ltd

18

나는 다른 사람들이 이미 이것에 대답했다는 것을 안다. 그러나 다른 사람들이 비슷한 문제를 겪을 수 있도록 도와주는 매우 중요한 요소는 다음과 같습니다.

onChange입력 필드에 핸들러를 추가 해야합니다 (예 : textField, 확인란, 라디오 등). onChange핸들러를 통해 항상 활동을 처리하십시오 .

예:

<input ... onChange={ this.myChangeHandler} ... />

확인란 으로 작업 할 때로checked 상태 를 처리해야 할 수도 있습니다 !!.

예:

<input type="checkbox" checked={!!this.state.someValue} onChange={.....} >

참조 : https://github.com/facebook/react/issues/6779#issuecomment-326314716


1
이것은 저에게 효과적입니다. 그렇습니다. 100 %는 동의합니다. 초기 상태는 {}이므로 확인 된 값은 정의되지 않고 제어되지 않습니다.
Ping Woo

13

이 문제를 해결하는 간단한 해결책은 기본적으로 빈 값을 설정하는 것입니다.

<input name='myInput' value={this.state.myInput || ''} onChange={this.handleChange} />

8

생성자에서 필드 값을 ""(빈 문자열)로 설정하면 발생할 수있는 단점은 필드가 선택적 필드이고 편집되지 않은 상태로 남아있는 것입니다. 양식을 게시하기 전에 일부 마사지를 수행하지 않으면 필드는 데이터 저장소에 NULL 대신 빈 문자열로 유지됩니다.

이 대안은 빈 문자열을 피합니다.

constructor(props) {
    super(props);
    this.state = {
        name: null
    }
}

... 

<input name="name" type="text" value={this.state.name || ''}/>

6

onChange={this.onFieldChange('name').bind(this)}입력에서 사용할 때는 상태 빈 문자열을 속성 필드 값으로 선언해야합니다.

잘못된 방법 :

this.state ={
       fields: {},
       errors: {},
       disabled : false
    }

올바른 방법 :

this.state ={
       fields: {
         name:'',
         email: '',
         message: ''
       },
       errors: {},
       disabled : false
    }

6

제 경우에는 정말 사소한 것이 빠져있었습니다.

<input value={state.myObject.inputValue} />

경고가 표시 될 때 상태는 다음과 같습니다.

state = {
   myObject: undefined
}

내 value의 입력참조하도록 내 상태를 번갈아 가면서 내 문제가 해결되었습니다.

state = {
   myObject: {
      inputValue: ''
   }
}

2
내가 가진 실제 문제를 이해하도록 도와 주셔서 감사합니다
rotimi-best

3

구성 요소의 소품이 상태로 전달 된 경우 입력 태그에 기본값을 입력하십시오.

<input type="text" placeholder={object.property} value={object.property ? object.property : ""}>


3

이것에 대한 업데이트. 반응 고리 사용const [name, setName] = useState(" ")


덕분에 4 업데이트 요르단이 오류는 해결하기 조금 어렵다
후안 살바도르

" "그렇지 ""않습니까? 이로 인해 힌트 텍스트가 손실되고, 클릭하고 입력하면 데이터를 입력하기 전에 빈 공간이 생깁니다.
Joshua Wade

1

이것은 일반적으로 응용 프로그램이 시작될 때 제출 된 파일의 값을 제어하지 않고 일부 이벤트 또는 일부 기능이 시작되거나 상태가 변경된 후에 만 ​​입력 필드의 값을 제어하려고 시도하는 경우에만 발생합니다.

입력을 제어 할 수없고 제어 할 수있는 전환은 처음에 문제가 발생하는 원인입니다.

이를 피하는 가장 좋은 방법은 구성 요소 생성자에서 입력 값을 선언하는 것입니다. 입력 요소는 응용 프로그램의 시작부터 값을 갖습니다.


0

양식 입력에 대한 상태 속성을 동적으로 설정하고 제어하기 위해 다음과 같이 할 수 있습니다.

const inputs = [
    { name: 'email', type: 'email', placeholder: "Enter your email"},
    { name: 'password', type: 'password', placeholder: "Enter your password"},
    { name: 'passwordConfirm', type: 'password', placeholder: "Confirm your password"},
]

class Form extends Component {
  constructor(props){
    super(props)
    this.state = {} // Notice no explicit state is set in the constructor
  }

  handleChange = (e) => {
    const { name, value } = e.target;

    this.setState({
      [name]: value
    }
  }

  handleSubmit = (e) => {
    // do something
  }

  render() {
     <form onSubmit={(e) => handleSubmit(e)}>
       { inputs.length ?
         inputs.map(input => {
           const { name, placeholder, type } = input;
           const value = this.state[name] || ''; // Does it exist? If so use it, if not use an empty string

           return <input key={name}  type={type} name={name} placeholder={placeholder} value={value} onChange={this.handleChange}/>
       }) :
         null
       }
       <button type="submit" onClick={(e) => e.preventDefault }>Submit</button>
     </form>    
  }
}

0

this.state.name이 null 인 경우 간단히 ''로 대체합니다.

<input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>

이것은 useState 변수와도 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.