Một thành phần đang thay đổi đầu vào văn bản loại không được kiểm soát thành lỗi được kiểm soát trong ReactJS


331

Cảnh báo: Một thành phần đang thay đổi đầu vào không kiểm soát của văn bản loại sẽ được kiểm soát. Các yếu tố đầu vào không nên chuyển từ không kiểm soát sang kiểm soát (hoặc ngược lại). Quyết định giữa việc sử dụng phần tử đầu vào được kiểm soát hoặc không được kiểm soát trong suốt vòng đời của thành phần. *

Sau đây là mã của tôi:

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">
      <input
        value={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>
  )
}

2
giá trị ban đầu của fieldsnhà nước là gì?
Mayank Shukla

2
constructor (đạo cụ) {super (đạo cụ); this.state = {field: {}, lỗi: {}} this.onSubmit = this.onSubmit.bind (this); }
Riya Kapuria

Câu trả lời:


650

Lý do là, trong trạng thái bạn xác định:

this.state = { fields: {} }

các trường dưới dạng một đối tượng trống, vì vậy trong lần hiển thị đầu tiên this.state.fields.namesẽ là undefinedvà trường đầu vào sẽ nhận giá trị của nó là:

value={undefined}

Do đó, trường đầu vào sẽ trở nên mất kiểm soát.

Khi bạn nhập bất kỳ giá trị nào vào đầu vào, fieldstrạng thái sẽ được thay đổi thành:

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

Và tại thời điểm đó, trường đầu vào được chuyển đổi thành một thành phần được kiểm soát; đó là lý do tại sao bạn nhận được lỗi:

Một thành phần đang thay đổi một kiểu nhập văn bản không kiểm soát được kiểm soát.

Phương pháp khả thi:

1- Xác định fieldstrạng thái là:

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

2- Hoặc xác định thuộc tính giá trị bằng cách sử dụng đánh giá ngắn mạch như thế này:

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

5
Có một lý do không xác định là "không kiểm soát" trong khi lý do sau là "được kiểm soát" - những điều này có nghĩa là gì?
Prashanth Subramanian

2
bởi vì ''là một giá trị chuỗi hợp lệ. vì vậy khi bạn thay đổi ''thành 'xyz', loại đầu vào không thay đổi có nghĩa là được kiểm soát thành kiểm soát. Nhưng trong trường hợp undefinedđể xyzloại sẽ thay đổi từ không kiểm soát sang kiểm soát.
Mayank Shukla

1
Cảm ơn bạn điều này đã làm việc cho tôi:value={this.state.fields.name || ''}
Bob

1
Tôi không biết rằng một khi giá trị trở nên không xác định, đầu vào sẽ tự động không được kiểm soát, Tuyệt vời. Đã khắc phục sự cố của tôi
Adrian Serna

1
kinh ngạc! bởi vì tôi đã không thấy điều này được đề cập trong các tài liệu chính thức, hay tôi bị mù? xin vui lòng liên kết đến nguồn :)
Dheeraj

34

Thay đổi valueđể defaultValuesẽ giải quyết nó.

Lưu ý :

defaultValuechỉ dành cho tải ban đầu. Nếu bạn muốn khởi tạo inputthì bạn nên sử dụng defaultValue, nhưng nếu bạn muốn sử dụng stateđể thay đổi giá trị thì bạn cần sử dụng value. Đọc này để biết thêm.

Tôi đã từng value={this.state.input ||""}inputđể thoát khỏi cảnh báo đó.


2
Cảm ơn bạn! Tôi đã gặp vấn đề này và các giải pháp khác không áp dụng cho tôi, nhưng giải pháp này đã giúp ích.
PepperAddict

14

Bên trong thành phần đặt hộp đầu vào theo cách sau.

<input className="class-name"
              type= "text"
              id="id-123"
              value={ this.state.value || "" }
              name="field-name"
              placeholder="Enter Name"
              />

13

ĐƠN GIẢN, Bạn phải đặt trạng thái ban đầu trước

Nếu bạn không đặt phản ứng trạng thái ban đầu sẽ coi đó là một thành phần không được kiểm soát


10

Ngoài câu trả lời được chấp nhận, nếu bạn đang sử dụng một inputloại checkboxhoặc radio, tôi thấy tôi cũng cần null / không xác định kiểm tra checkedthuộc tính.

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

Và nếu bạn đang sử dụng TS (hoặc Babel), bạn có thể sử dụng kết hợp nullish thay vì toán tử OR logic:

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

8

Đặt trạng thái hiện tại trước ...this.state

Đó là bởi vì khi bạn định gán một trạng thái mới, nó có thể không được xác định. do đó, nó sẽ được sửa bằng cách đặt trạng thái trích xuất trạng thái hiện tại

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

Nếu có một đối tượng trong trạng thái của bạn, bạn nên đặt trạng thái như sau, giả sử bạn phải đặt tên người dùng bên trong đối tượng người dùng.

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

1
Theo như tôi hiểu, setState đã chỉ ghi đè các trường, vì vậy trong trường hợp đầu tiên, không cần thiết phải hủy cấu trúc gán. Ở trạng thái thứ hai, có thể cần thiết vì setState sẽ thay thế bán buôn đối tượng phụ.
Kzqai

6
const [name, setName] = useState()

tạo ra lỗi ngay khi bạn nhập vào trường văn bản

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

sẽ khắc phục vấn đề trên ví dụ chuỗi này.


2

Nếu bạn sử dụng nhiều đầu vào trên trường, hãy làm theo: Ví dụ:

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>
     ); 
  }
}

Tìm kiếm vấn đề của bạn tại:

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

1

Sử dụng React Hook cũng không quên đặt giá trị ban đầu.
Tôi đã sử dụng <input type='datetime-local' value={eventStart} />và ban đầu eventStartlà như thế

const [eventStart, setEventStart] = useState();
thay vào đó
const [eventStart, setEventStart] = useState('');.

Chuỗi rỗng trong ngoặc là sự khác biệt.
Ngoài ra, nếu bạn đặt lại biểu mẫu sau khi gửi như tôi, một lần nữa bạn cần đặt nó thành chuỗi trống, không chỉ là dấu ngoặc đơn.

Đây chỉ là đóng góp nhỏ của tôi cho chủ đề này, có thể nó sẽ giúp được ai đó.


0

Trong trường hợp của tôi, đó là câu trả lời hàng đầu của Mayank Shukla. Chi tiết duy nhất là nhà nước của tôi thiếu hoàn toàn tài sản mà tôi đang xác định.

Ví dụ: nếu bạn có trạng thái này:

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

Nếu bạn đang mở rộng mã của bạn, bạn có thể muốn thêm một chỗ dựa mới như vậy, một nơi nào đó khác trong mã của bạn, bạn có thể tạo ra một tài sản mới ccó giá trị không chỉ không xác định về tình trạng của thành phần nhưng tài sản riêng của mình là undefined.

Để giải quyết điều này, chỉ cần đảm bảo thêm cvào trạng thái của bạn và cung cấp cho nó một giá trị ban đầu thích hợp.

ví dụ,

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

Hy vọng tôi đã có thể giải thích trường hợp cạnh của tôi.


0

Tôi nhận được cảnh báo tương tự: Một thành phần đang thay đổi đầu vào không được kiểm soát của loại ẩn được kiểm soát. Tôi không thể khắc phục vấn đề của mình. Bất cứ ý tưởng tại sao?

export default ({  valueName, onChangeAllg,}) => {

          <TextField
            id={"name"}
            select
            label={"name"}
            value={valueName.geschlecht || ""}
            name={"name"}
            onChange={onChangeAllg}

          >
            {nameList.map((option) => (
              <MenuItem key={option.value} value={option.value}>
                {option.label}
              </MenuItem>
            ))}
          </TextField>

tôi đã thử ({ valueName, valueName: {geschlecht=""}, onChangeAllg,})value={valueName.geschlecht || ""}


tôi đã tìm thấy nó Một phần defaultValue={""}bên trong của TextField đã bị mất
Tiến sĩ Malte Westerloh

0

Cảnh báo: Một thành phần đang thay đổi đầu vào không kiểm soát của văn bản loại sẽ được kiểm soát. Các yếu tố đầu vào không nên chuyển từ không kiểm soát sang kiểm soát (hoặc ngược lại). Quyết định giữa việc sử dụng một yếu tố đầu vào được kiểm soát hoặc không được kiểm soát trong suốt vòng đời của thành phần.

Giải pháp: Kiểm tra nếu giá trị không được xác định

Phản ứng / Formik / Bootstrap / TypeScript

thí dụ :

{ values?.purchaseObligation.remainingYear ?
  <Input
   tag={Field}
   name="purchaseObligation.remainingYear"
   type="text"
   component="input"
  /> : null
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.