Tepki - kontrolsüz bir girişi değiştirme


360

Ben bir kontrollü girdi olduğuna inanıyorum formu ile basit bir tepki bileşeni var:

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;

Uygulamamı çalıştırdığımda aşağıdaki uyarıyı alıyorum:

Uyarı: MyForm, kontrol edilecek tip metinlerin kontrolsüz bir girişini değiştiriyor. Giriş elemanları kontrolsüzden kontrollü (veya tam tersi) olmamalıdır. Bileşenin ömrü boyunca kontrollü veya kontrolsüz giriş öğesi kullanma arasında karar verme

İnanıyorum ki girdim kontrol ediliyor çünkü bir değeri var. Neyi yanlış yaptığımı merak ediyorum?

React 15.1.0 kullanıyorum

Yanıtlar:


510

İnanıyorum ki girdim kontrol ediliyor çünkü bir değeri var.

Bir girişin kontrol edilebilmesi için değeri bir durum değişkeninin değerine karşılık gelmelidir.

this.state.nameBaşlangıçta ayarlanmadığından, bu koşul başlangıçta örneğinizde karşılanmaz . Bu nedenle, girdi başlangıçta kontrolsüzdür. Bir kez onChangeişleyicisi ilk kez tetiklenir, this.state.nameset alır. Bu noktada, yukarıdaki koşul yerine getirilir ve girdinin kontrol edildiği kabul edilir. Kontrolsüzden kontrol edilene bu geçiş, yukarıda görülen hatayı üretir.

Yapıcıda başlatarak this.state.name:

Örneğin

this.state = { name: '' };

giriş, sorunu düzelterek baştan kontrol edilir. Daha fazla örnek için Reaksiyon Kontrollü Bileşenlere bakın .

Bu hatayla alakasız, yalnızca bir varsayılan dışa aktarmanız gerekir. Yukarıdaki kodunuzda iki tane vardır.


7
Cevabı okumak ve fikri defalarca takip etmek zordur, ancak bu cevap hikayeyi anlatmak ve izleyiciyi aynı anda anlamayı sağlamak için mükemmel bir yoldur. Seviye tanrıya cevap ver!
surajnew55

2
Bir döngüde dinamik alanlarınız varsa ne olur? örneğin alan adını name={'question_groups.${questionItem.id}'}?
user3574492

2
Dinamik alanlar nasıl çalışır? Formu dinamik olarak oluşturuyor ve daha sonra durum içindeki bir nesnede alan adlarını ayarlıyorum, yine de önce ilk olarak alan adlarını manuel olarak ayarlayıp sonra bunları nesneme aktarmam gerekiyor mu?
Joseph

13
Bu cevap biraz yanlış. Pervane boş / tanımsız bir değere sahipsevalue giriş kontrol edilir . Prop bir durum değişkenine karşılık gelmek zorunda değildir (sadece sabit olabilir ve bileşen hala kontrollü olarak kabul edilir). Adam'ın cevabı daha doğru ve kabul edilmelidir.
ecraig12345

2
Evet - bu teknik olarak yanlış cevap (ama yararlı). Bununla ilgili bir not - radyo düğmeleriyle uğraşıyorsanız ('değeri' biraz farklı kontrol edilir), bu tepki uyarısı, bileşeniniz kontrol edilmiş olsa bile (şu anda) gerçekten atılabilir. github.com/facebook/react/issues/6779 ve bir ekleyerek düzeltilebilir !! isChecked
mheavers

123

Öncelikle bileşeni işlediğinizde this.state.nameo kadar değerlendirir, böylece ayarlı değil undefinedya nullve geçen sonunda value={undefined}veya value={null}To Your input.

Bir alan kontrol edilir, eğer ReactDOM denetler zaman o çekleri görmek içinvalue != null (o olduğunu not !=değil !==), ve o zamandan beri undefined == nullJavaScript, buna kontrolsüz olduğunu karar verir.

Bu nedenle, onFieldChange()çağrıldığında, this.state.namebir dize değerine ayarlandığında, girişiniz kontrolsüz olmaktan kontrol edilmeye gider.

Yapıcıda yaparsanız this.state = {name: ''}, çünkü '' != nullgirdiniz her zaman bir değere sahip olacak ve bu mesaj kaybolacaktır.


5
Değeri için, aynı şey olabilir this.props.<whatever>, bu da benim sorunumdu. Teşekkürler, Adam!
Don

Evet! Bu, tanımladığınız hesaplanmış bir değişkeni render()veya etiketin kendisinde bir ifadeyi (değerlendirilen herhangi bir şeyi) iletirseniz de olabilir undefined. Yardımcı olduğuma sevindim!
Leigh Brenecki

1
Bu cevap için teşekkürler: Kabul edilen cevap olmasa da, sorunu sadece "belirtin" den çok daha iyi açıklar name.
machineghost

1
Kontrollü girdinin nasıl çalıştığını açıklamak için cevabımı güncelledim. Burada önemli olanın undefined, başlangıçta bir değerinin geçirilmesinin olmadığını belirtmek gerekir . Daha ziyade, this.state.namegirişi kontrolsüz hale getiren bir durum değişkeni olarak mevcut değildir. Örneğin this.state = { name: undefined };, girişin kontrol edilmesiyle sonuçlanır. Anlaşılması gereken, değerin nereden geldiğinin değil, değerin nereden geldiği.
fvgs

1
@fvgs this.state = { name: undefined }hala denetlenmeyen bir girdiyle sonuçlanır. <input value={this.state.name} />desugarlar React.createElement('input', {value: this.state.name}). Bir nesnenin varolmayan bir özelliğine erişim döndürdüğünden undefined, bu tam olarak aynı işlev çağrısına ( React.createElement('input', {value: undefined})—yayarsız nameveya açık olarak ayarlı olsun) göre değerlendirilir, bu undefinednedenle React aynı şekilde davranır. Bu davranışı bu JSFiddle'da görebilirsiniz.
Leigh Brenecki

52

Başka bir yaklaşım, girişinizin içindeki varsayılan değeri ayarlamak olabilir, örneğin:

 <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)} /> Bunun da işe yarayacağını düşünüyorum
gandalf

Çok teşekkürler, bu tam olarak aradığım şeydi. Aklımda tutmam gereken bu modeli kullanmanın herhangi bir dezavantajı veya olası sorunu var mı?
Marcel Otten

Alanlar API'den dinamik olarak işlendiğinden, bileşen monte edildiğinde alanın adını bilmediğim için bu benim için çalıştı. Bu bir tedavi çalıştı!
Jamie - Fenrir Digital Ltd

18

Başkalarının bunu zaten yanıtladığını biliyorum. Ancak burada benzer sorun yaşayan diğer insanlara yardımcı olabilecek çok önemli bir faktör:

onChangeGiriş alanınıza bir işleyici eklenmelidir (örn. TextField, onay kutusu, radyo vb.). Etkinliği her zaman onChangeişleyici aracılığıyla gerçekleştirin .

Misal:

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

Onay kutusuyla çalışırken checkeddurumunu ele almanız gerekebilir !!.

Misal:

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

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


1
Bu benim için çalışıyor, teşekkürler, evet, yüzde 100 katılıyorum, başlangıç ​​durumu {}, bu yüzden kontrol edilen değer tanımsız olacak ve kontrolsüz hale getirilecek,
Ping Woo

13

Bu sorunu çözmek için basit bir çözüm, varsayılan olarak boş bir değer belirlemektir:

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

8

Alan değerini yapıcıda "" (boş dize) olarak ayarlamanın olası bir dezavantajı, alanın isteğe bağlı bir alan olması ve düzenlenmemiş olarak bırakılmasıdır. Formunuzu göndermeden önce biraz masaj yapmadığınız sürece, alan veri depolama alanınıza NULL yerine boş bir dize olarak kalır.

Bu alternatif boş dizeleri önleyecektir:

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

... 

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

6

Girişinizde kullandığınızda onChange={this.onFieldChange('name').bind(this)}, durum boş dizenizi özellik alanının değeri olarak bildirmeniz gerekir.

yanlış yol:

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

doğru yol:

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

6

Benim durumumda, gerçekten önemsiz bir şey eksikti.

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

Uyarıyı alırken durumum şu şekildeydi:

state = {
   myObject: undefined
}

Durumumu, değerimin girdisine referans gösterecek şekilde değiştirerek , sorunum çözüldü:

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


3

Bileşeninizdeki sahne öğeleri durum olarak iletildiyse, giriş etiketleriniz için varsayılan bir değer koyun

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


3

Bunun için bir güncelleme. Reaksiyon Kancaları kullanımı içinconst [name, setName] = useState(" ")


Teşekkürler 4 güncelleme Ürdün, bu hatayı çözmek biraz zor
Juan Salvador

Neden " "olmasın ""? Bu, ipucu metnini kaybetmenize neden olur ve tıklayıp yazarsanız, girdiğiniz verilerden önce gizli bir alan elde edersiniz.
Joshua Wade

1

Bu genellikle yalnızca uygulama başlatıldığında dosyalanan değeri kontrol etmediğinizde ve bir olay ya da bir işlev tetiklendikten ya da durum değiştikten sonra artık giriş alanındaki değeri kontrol etmeye çalışıyorsunuz.

Girdi üzerinde kontrol sahibi olmama ve daha sonra kontrol üzerinde bulunmama geçişi, sorunun ilk etapta gerçekleşmesine neden olan şeydir.

Bundan kaçınmanın en iyi yolu, bileşenin yapıcısındaki girdi için bir değer bildirmektir. Böylece giriş elemanı uygulamanın başlangıcından itibaren bir değere sahip olur.


0

Form girişleri için durum özelliklerini dinamik olarak ayarlamak ve bunları kontrol altında tutmak için şöyle bir şey yapabilirsiniz:

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 boşsa '' için bir yedek oluşturun.

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

Bu, useState değişkenleriyle de çalışır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.