คอมโพเนนต์กำลังเปลี่ยนอินพุตที่ไม่ได้ควบคุมของข้อความชนิดที่จะควบคุมข้อผิดพลาดใน ReactJS


331

คำเตือน: ส่วนประกอบกำลังเปลี่ยนอินพุตที่ไม่ได้ควบคุมของข้อความประเภทที่จะควบคุม องค์ประกอบอินพุตไม่ควรเปลี่ยนจากไม่มีการควบคุมเป็นการควบคุม (หรือในทางกลับกัน) ตัดสินใจเลือกระหว่างการใช้อิลิเมนต์อินพุตที่ควบคุมหรือไม่มีการควบคุมสำหรับอายุการใช้งานของส่วนประกอบ *

ต่อไปนี้เป็นรหัสของฉัน:

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
ค่าเริ่มต้นของfieldsในรัฐคืออะไร?
Mayank Shukla

2
ตัวสร้าง (อุปกรณ์ประกอบฉาก) {super (อุปกรณ์ประกอบฉาก); this.state = {เขตข้อมูล: {}, ข้อผิดพลาด: {}} this.onSubmit = this.onSubmit.bind (นี้); }
Riya Kapuria

คำตอบ:


650

เหตุผลคือในสถานะที่คุณกำหนด:

this.state = { fields: {} }

เขตข้อมูลเป็นวัตถุว่างดังนั้นระหว่างการเรนเดอร์แรกthis.state.fields.nameจะเป็นundefinedและฟิลด์อินพุตจะได้รับค่าเป็น:

value={undefined}

ด้วยเหตุนี้ฟิลด์อินพุตจะไม่สามารถควบคุมได้

เมื่อคุณป้อนค่าใด ๆ ในอินพุตfieldsสถานะจะเปลี่ยนเป็น:

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

และในเวลานั้นฟิลด์อินพุตจะถูกแปลงเป็นองค์ประกอบที่มีการควบคุม นั่นเป็นสาเหตุที่คุณได้รับข้อผิดพลาด:

คอมโพเนนต์กำลังเปลี่ยนอินพุตที่ไม่ได้ควบคุมของข้อความประเภทที่จะควบคุม

การแก้ปัญหาที่เป็นไปได้:

1- กำหนดfieldsสถานะเป็น:

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

2- หรือกำหนดคุณสมบัติค่าโดยใช้การประเมินการลัดวงจรเช่นนี้

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

5
มีเหตุผลที่ไม่ได้กำหนดว่า "ไม่สามารถควบคุมได้" ในขณะที่ส่วนหลังคือ "ควบคุม" - สิ่งเหล่านี้หมายความว่าอย่างไร
Prashanth Subramanian

2
เพราะ''เป็นค่าสตริงที่ถูกต้อง ดังนั้นเมื่อคุณเปลี่ยน''เป็น 'xyz' ประเภทอินพุตจะไม่เปลี่ยนแปลงหมายความว่าควบคุมเป็นควบคุม แต่ในกรณีที่undefinedจะxyzพิมพ์จะเปลี่ยนจากควบคุมไม่ได้เพื่อควบคุม
Mayank Shukla

1
ขอบคุณสิ่งนี้ได้ผลกับฉัน:value={this.state.fields.name || ''}
Bob

1
ฉันไม่รู้ว่าเมื่อค่ากลายเป็นไม่ได้กำหนดอินพุตจะไม่ได้รับการควบคุมโดยอัตโนมัติยอดเยี่ยม แก้ไขปัญหาของฉันแล้ว
Adrian Serna

1
! ที่น่าตื่นตาตื่นใจ เพราะฉันไม่เห็นสิ่งนี้ถูกกล่าวถึงในเอกสารอย่างเป็นทางการหรือฉันตาบอด? เชื่อมโยงไปยังแหล่งที่มาโปรด :)
Dheeraj

34

การเปลี่ยนvalueเป็นdefaultValueจะแก้ปัญหา

หมายเหตุ :

defaultValueใช้สำหรับการโหลดครั้งแรกเท่านั้น หากคุณต้องการที่จะเริ่มต้นinputแล้วคุณควรใช้defaultValueแต่ถ้าคุณต้องการที่จะใช้เพื่อเปลี่ยนค่าแล้วคุณจะต้องใช้state valueอ่านเรื่องนี้มานาน

ผมใช้value={this.state.input ||""}ในinputการกำจัดคำเตือนว่า


2
ขอบคุณ! ฉันเจอปัญหานี้และวิธีแก้ไขปัญหาอื่นไม่ได้ใช้กับฉัน แต่วิธีนี้ช่วยได้
PepperAddict

14

ภายในส่วนประกอบให้ใส่กล่องอินพุตด้วยวิธีต่อไปนี้

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

13

ง่ายคุณต้องตั้งค่าสถานะเริ่มต้นก่อน

หากคุณไม่ได้ตั้งค่าสถานะเริ่มต้นการตอบสนองจะถือว่าเป็นองค์ประกอบที่ไม่สามารถควบคุมได้


10

นอกจากคำตอบที่ได้รับการยอมรับหากคุณใช้inputประเภทใดประเภทหนึ่งcheckboxหรือradioพบว่าฉันจำเป็นต้องมีค่าว่าง / ไม่ได้กำหนดให้ตรวจสอบcheckedแอตทริบิวต์เช่นกัน

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

และถ้าคุณใช้ TS (หรือ Babel) คุณสามารถใช้การรวมกลุ่มแบบ nullish แทนตัวดำเนินการ OR หรือตรรกะ:

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

8

ตั้งค่าสถานะปัจจุบันก่อน ...this.state

มันเป็นเพราะเมื่อคุณจะกำหนดสถานะใหม่มันอาจจะไม่ได้กำหนด ดังนั้นมันจะได้รับการแก้ไขโดยการตั้งค่าสถานะการแยกสถานะปัจจุบันด้วย

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

หากมีวัตถุในรัฐของคุณคุณควรตั้งค่าสถานะดังต่อไปนี้สมมติว่าคุณต้องตั้งชื่อผู้ใช้ภายในวัตถุผู้ใช้

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

1
เท่าที่ฉันเข้าใจ setState แล้วแทนที่เฉพาะฟิลด์ดังนั้นในกรณีแรกมันไม่จำเป็นต้อง destruct มอบหมาย ในสถานะที่สองอาจจำเป็นเนื่องจาก setState จะแทนที่ sub-object wholesale
Kzqai

6
const [name, setName] = useState()

สร้างข้อผิดพลาดทันทีที่คุณพิมพ์ในฟิลด์ข้อความ

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

จะแก้ไขปัญหาในตัวอย่างสตริงนี้


2

หากคุณใช้อินพุตหลายอินในฟิลด์ให้ปฏิบัติตามตัวอย่างเช่น:

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

1

การใช้React Hooksก็อย่าลืมตั้งค่าเริ่มต้น
ฉันใช้<input type='datetime-local' value={eventStart} />และเริ่มต้นeventStartเป็นเหมือน

const [eventStart, setEventStart] = useState();

const [eventStart, setEventStart] = useState('');แทน

สตริงว่างในวงเล็บคือความแตกต่าง
นอกจากนี้หากคุณรีเซ็ตฟอร์มหลังจากส่งเหมือนที่ฉันทำอีกครั้งคุณต้องตั้งเป็นสตริงว่างเปล่าไม่ใช่แค่วงเล็บว่างเปล่า

นี่เป็นเพียงส่วนเล็ก ๆ ของฉันในหัวข้อนี้อาจจะช่วยใครซักคน


0

ในกรณีของฉันมันค่อนข้างจะเป็นสิ่งที่คำตอบยอดนิยมของ Mayank Shukla พูด รายละเอียดเพียงอย่างเดียวก็คือว่ารัฐของฉันขาดคุณสมบัติที่ฉันกำหนดอย่างสมบูรณ์

ตัวอย่างเช่นหากคุณมีสถานะนี้:

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

หากคุณกำลังขยายรหัสของคุณคุณอาจต้องการเพิ่มเสาใหม่ดังนั้นบางแห่งในรหัสของคุณคุณอาจสร้างคุณสมบัติใหม่cที่มีค่าไม่เพียงไม่ได้กำหนดในสถานะขององค์ประกอบ แต่คุณสมบัติของตัวเองไม่ได้กำหนด

เพื่อแก้ปัญหานี้ให้แน่ใจว่าได้เพิ่มcเข้าไปในสถานะของคุณและให้ค่าเริ่มต้นที่เหมาะสม

เช่น,

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

หวังว่าฉันจะสามารถอธิบายกรณีขอบของฉัน


0

ฉันได้รับคำเตือนแบบเดียวกัน: ส่วนประกอบกำลังเปลี่ยนอินพุตที่ไม่ได้ควบคุมประเภทที่ซ่อนอยู่ซึ่งถูกควบคุม ฉันไม่สามารถแก้ไขปัญหาได้ ความคิดใดทำไม

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>

ฉันพยายาม({ valueName, valueName: {geschlecht=""}, onChangeAllg,})แล้วvalue={valueName.geschlecht || ""}


เจอแล้ว. defaultValue={""}ภายในของ TextField ก็หายไป
ดร. Malte Westerloh

0

คำเตือน: ส่วนประกอบกำลังเปลี่ยนอินพุตที่ไม่ได้ควบคุมของข้อความประเภทที่จะควบคุม องค์ประกอบอินพุตไม่ควรเปลี่ยนจากไม่มีการควบคุมเป็นการควบคุม (หรือในทางกลับกัน) ตัดสินใจระหว่างการใช้อิลิเมนต์อินพุตที่ควบคุมหรือไม่มีการควบคุมสำหรับอายุการใช้งานของคอมโพเนนต์

การแก้ไข: ตรวจสอบว่าค่าไม่ได้ไม่ได้กำหนด

ทำปฏิกิริยา / Formik / Bootstrap / TypeScript

ตัวอย่าง:

{ values?.purchaseObligation.remainingYear ?
  <Input
   tag={Field}
   name="purchaseObligation.remainingYear"
   type="text"
   component="input"
  /> : null
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.