प्रतिक्रिया - एक अनियंत्रित इनपुट को बदलना


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 नियंत्रित करने के लिए टाइप टेक्स्ट के अनियंत्रित इनपुट को बदल रहा है। इनपुट तत्वों को अनियंत्रित से नियंत्रित (या इसके विपरीत) पर स्विच नहीं करना चाहिए। घटक के जीवनकाल के लिए नियंत्रित या अनियंत्रित इनपुट तत्व का उपयोग करने के बीच का निर्णय लें

मेरा मानना ​​है कि मेरा इनपुट नियंत्रित है क्योंकि इसका मूल्य है। मैं सोच रहा हूं कि मैं क्या गलत कर रहा हूं?

मैं 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
गतिशील क्षेत्र कैसे काम करेंगे। क्या रूप को गतिशील रूप से उत्पन्न कर रहा है और फिर फ़ील्ड नामों को राज्य के अंदर किसी ऑब्जेक्ट में सेट करता है, क्या मुझे अभी भी पहले फ़ील्ड नामों को पहले राज्य में सेट करना है और फिर उन्हें मेरी ऑब्जेक्ट में स्थानांतरित करना है?
जोसफ

13
यह उत्तर थोड़ा गलत है। एक इनपुट को नियंत्रित किया जाता है अगर valueप्रोप में एक गैर-अशक्त / अपरिभाषित मूल्य है। प्रस्ताव को राज्य चर के अनुरूप होने की आवश्यकता नहीं है (यह सिर्फ एक स्थिर हो सकता है और घटक को अभी भी नियंत्रित माना जाएगा)। एडम का जवाब अधिक सही है और इसे स्वीकार किया जाना चाहिए।
ecraig12345

2
हाँ - यह तकनीकी रूप से गलत उत्तर (लेकिन सहायक) है। इस पर एक नोट - यदि आप रेडियो बटन (जिनके 'मूल्य' को थोड़ा अलग तरीके से नियंत्रित किया जाता है) के साथ काम कर रहे हैं, तो यह प्रतिक्रिया चेतावनी वास्तव में फेंक सकती है भले ही आपका घटक नियंत्रित हो (वर्तमान में)। github.com/facebook/react/issues/6779 , और एक जोड़कर तय किया जा सकता है !! की सच्चाई की जाँच की
सांसदों

122

जब आप पहली बार अपने घटक को प्रस्तुत करते हैं, 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>, जो मेरे अंत में समस्या थी। धन्यवाद, एडम!
डॉन

हां! यह तब भी हो सकता है जब आप एक परिकलित चर को पास करते हैं जिसे आप परिभाषित करते हैं render(), या टैग में एक अभिव्यक्ति है - जो कुछ भी मूल्यांकन करता है undefined। मैं खुशी से मदद कर सकता है!
लेह ब्रीनेकी

1
इस उत्तर के लिए धन्यवाद: भले ही इसे स्वीकार नहीं किया गया हो, यह इस मुद्दे को सिर्फ "निर्दिष्ट करें" से बेहतर बताता है name
मशीनगॉस्ट

1
नियंत्रित इनपुट कैसे काम करता है, यह समझाने के लिए मैंने अपना उत्तर अपडेट किया है। यह ध्यान देने योग्य है कि यहां जो मायने रखता है वह यह नहीं है कि undefinedशुरू में इसका एक मूल्य पारित किया जाता है। बल्कि, यह वह तथ्य है जो उस this.state.nameराज्य चर के रूप में मौजूद नहीं है जो इनपुट को अनियंत्रित बनाता है। उदाहरण के लिए, this.state = { name: undefined };इनपुट नियंत्रित होने के परिणामस्वरूप होगा। यह समझा जाना चाहिए कि मूल्य कहां से आता है, क्या मायने रखता है, न कि मूल्य क्या है।
15

1
@fvgs होने के this.state = { name: undefined }बाद भी अनियंत्रित इनपुट होगा। <input value={this.state.name} />करने के लिए desugars React.createElement('input', {value: this.state.name})। क्योंकि एक वस्तु रिटर्न में गैर-मौजूद प्रॉपर्टी एक्सेस undefined, ठीक उसी समारोह कॉल करने के लिए इस मूल्यांकन करता है React.createElement('input', {value: undefined})कि क्या nameसेट नहीं है या स्पष्ट रूप से करने के लिए सेट undefinedहै, तो उसी तरह से बर्ताव करती प्रतिक्रिया। आप इस व्यवहार को इस JSFiddle में देख सकते हैं।
लेह ब्रीनेकी

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 (यह)} /> मुझे लगता है कि यह भी काम करेगा
gandalf

बहुत बहुत धन्यवाद, यह वही था जिसकी मुझे तलाश थी। क्या इस पैटर्न का उपयोग करने में कोई असुविधा या संभावित समस्याएं हैं जिन्हें मुझे ध्यान में रखना चाहिए?
मार्सेल ओटेन

यह मेरे लिए काम कर रहा है, क्योंकि फ़ील्ड्स को एपीआई से गतिशील रूप से प्रदान किया जाता है, इसलिए मुझे घटक के माउंट होने पर फ़ील्ड का नाम नहीं पता है। यह एक इलाज काम किया!
जेमी - फेनरीर डिजिटल लिमिटेड

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
}

मेरे मूल्य के इनपुट को संदर्भित करने के लिए मेरे राज्य को वैकल्पिक करके , मेरी समस्या हल हो गई थी:

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

2
वास्तविक समस्या को समझने में मेरी मदद करने के लिए धन्यवाद
रोटिमी-बेस्ट

3

यदि आपके घटक पर रंगमंच की सामग्री को एक राज्य के रूप में पारित किया गया था, तो अपने इनपुट टैग के लिए डिफ़ॉल्ट मान डालें

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


3

इसके लिए एक अपडेट। रिएक्ट हुक के लिए उपयोग करेंconst [name, setName] = useState(" ")


धन्यवाद 4 अद्यतन जॉर्डन, इस त्रुटि को हल करने के लिए थोड़ा मुश्किल है
जुआन सल्वाडोर

क्यों " "और क्या नहीं ""? यह आपको किसी भी संकेत पाठ को खोने का कारण बनता है, और यदि आप क्लिक करते हैं और टाइप करते हैं तो आपके द्वारा दर्ज किए गए किसी भी डेटा से पहले आपको एक डरपोक स्थान मिलता है।
जोशुआ वेड

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

यदि यह .state.name शून्य है, तो बस '' पर एक वापसी करें।

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

यह भी उपयोग के साथ काम करता है चर चर।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.