React.js form bileşenlerinde state veya refs kullanılsın mı?


116

React.js ile başlıyorum ve basit bir form yapmak istiyorum ancak belgelerde bunu yapmanın iki yolunu buldum.

Birincisi kullanarak refs :

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

Ve ikincisi kullanıyor devlet bileşeni tepki içeride:

var TodoTextInput = React.createClass({
  getInitialState: function() {
    return {
      value: this.props.value || ''
    };
  },

  render: function() /*object*/ {
    return (
      <input className={this.props.className}
      id={this.props.id}
      placeholder={this.props.placeholder}
      onBlur={this._save}
      value={this.state.value}
      />
    );
  },

  _save: function() {
    this.props.onSave(this.state.value);
    this.setState({value: ''
  });
});

Bazıları varsa, iki alternatifin artılarını ve eksilerini göremiyorum. Teşekkürler.


Burada bir şey mi kaçırıyorum? Form değerlerini almak için neden olay nesnesini kullanmıyorsunuz? İlk etapta burada bir form kullanmanın tek nedeni bu gibi görünüyor. Varsayılan gönderme davranışını kullanmıyorsanız ve girdiler üzerinde referanslarınız varsa, bunları bir forma sarmanıza gerek yoktur.
NectarSoft

Yanıtlar:


143

Kısa versiyon: referanslardan kaçının.


Sürdürülebilirlik açısından kötüdürler ve WYSIWYG model oluşturmanın sağladığı basitliğin çoğunu kaybederler.

Bir formunuz var. Formu sıfırlayan bir düğme eklemeniz gerekir.

  • ref:
    • DOM'u değiştirmek
    • render, formun 3 dakika önce nasıl göründüğünü açıklıyor
  • durum
    • setState
    • render, formun nasıl göründüğünü açıklar

Bir girişte bir CCV numarası alanınız ve uygulamanızda sayı olan diğer bazı alanlar var. Şimdi kullanıcıyı sadece sayıları girmeye zorlamanız gerekiyor.

  • ref:
    • bir onChange işleyicisi ekleyin (bundan kaçınmak için ref kullanmıyor muyuz?)
    • bir sayı değilse dom'u onChange içinde değiştirin
  • durum
    • zaten bir onChange işleyiciniz var
    • bir if ifadesi ekleyin, eğer geçersizse hiçbir şey yapmayın
    • render yalnızca farklı bir sonuç üretecekse çağrılır

Eh, boşver, Başbakan bizden eğer geçersizse kırmızı bir kutu gölgesi yapmamızı istiyor.

  • ref:
    • make onChange işleyicisini sadece forceUpdate veya başka bir şey çağırır mısınız?
    • ... dayalı render çıktısı yapmak, ha?
    • render'da doğrulamak için değeri nereden alırız?
    • bir elemanın className dom özelliğini el ile değiştirmek?
    • kayboldum
    • referans olmadan yeniden yazılsın mı?
    • Eğer bağlanırsak, domtan render'da okuduktan sonra geçerli olduğunu varsayalım mı?
  • durum:
    • if ifadesini kaldırın
    • this.state'e göre render doğrulaması yap

Kontrolü ebeveyne geri vermeliyiz. Veriler artık sahne alıyor ve değişikliklere tepki vermemiz gerekiyor.

  • ref:
    • componentDidMount, componentWillUpdate ve componentDidUpdate'i uygulayın
    • önceki sahne donanımlarını manuel olarak ayırt
    • domu minimum değişikliklerle manipüle edin
    • Hey! react in react'i uyguluyoruz ...
    • dahası var ama parmaklarım ağrıyor
  • durum:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

İnsanlar hakemlerin durumu korumaktan 'daha kolay' olduğunu düşünüyor. Bu ilk 20 dakika için doğru olabilir, bundan sonraki deneyimimde doğru değil. Kendinizi "Tabii, birkaç bileşeni yeniden yazacağım" yerine "Evet, 5 dakika içinde bitireceğim" diyecek bir konuma koyun.


3
Sed -e 's / this.state / this.props /' 's / handleChange / onChange /' -i form.js hakkında biraz daha açıklayabilir misiniz?
gabrielgiussi

1
Hayır, domdaki gerçek değişiklikleri kastediyorum. React.findDOMNode(this.refs.foo). Örneğin değiştirirseniz, this.refs.foo.props.barhiçbir şey olmayacaktır.
Brigand

1
örneğin varsa <input onChange={this.handleChange} value={this.state.foo} />bunu değiştirmek <input onChange={this.props.handleChange} value={this.props.foo} />veya sahne içinde geri arama (lar) aramak için handleChange işlev (ler) değiştirin. Her iki durumda da, birkaç küçük bariz değişiklik.
Brigand

4
Cevabınızı biraz kafa karıştırıcı bulan tek kişi ben miyim emin değilim. Noktalarınızı daha net hale getiren bazı kod örnekleri gösterebilir misiniz?
Rishabh

2
Bir ekranda 50'den fazla girişin olması ve her birinin herhangi bir durum değişikliğinde görüntülenmesi arzu edilmez. Her inputbirinin kendi durumunu koruduğu her alanı bileşen haline getirmek idealdir. Bir noktada, bu çeşitli bağımsız durumları daha büyük bir modelle uzlaştırmamız gerekiyor. Belki bir zamanlayıcıda otomatik kaydetmemiz var, ya da sadece tasarruf ediyoruz. İdeal componentWillUnmountbulduğum yer burası refs, uzlaşma sırasında stateher birinden değeri alıyoruz refve hiçbiri daha akıllıca değil. Çoğu durumda statecevabın bu olduğuna katılıyorum , ancak çok sayıda, inputsuygun bir refsmodel kullanmak bir performans nimetidir
lux

105

Birkaç kişinin yukarıdaki cevabı "referansları asla kullanmamaları" için bir neden olarak gösterdiğini gördüm ve benim (ve konuştuğum diğer birkaç React geliştiricisinin yanı sıra) fikrimi vermek istiyorum.

"Referansları kullanma" yaklaşımı, bileşen örnekleri için bunları kullanmaktan bahsederken doğrudur. Yani, bileşen örneklerini yakalamanın ve bunlara yöntemler çağırmanın bir yolu olarak ref kullanmamalısınız. Bu, referansları kullanmanın yanlış yoludur ve referanslar hızlı bir şekilde güneye gittiği zamandır.

Referansları kullanmanın doğru (ve çok kullanışlı) yolu, onları DOM'dan bir değer elde etmek için kullandığınız zamandır. Örneğin, bu girişe bir ref ekleyen bir giriş alanınız varsa, değeri daha sonra ref aracılığıyla almak yeterlidir. Bu yol olmadan, girdi alanınızı yerel eyaletinizle veya akış deponuzla güncel tutmak için oldukça düzenlenmiş bir süreçten geçmeniz gerekir - ki bu gereksiz görünüyor.

2019 düzenlemesi: Merhaba geleceğin arkadaşları. Birkaç yıl önce ^ React Hooks ile bahsettiğime ek olarak, referanslar renderlar arasındaki verileri takip etmenin harika bir yoludur ve sadece DOM düğümlerini kapmakla sınırlı değildir.


3
Son paragrafınız çok mantıklı, ancak ikinci paragrafınızı netleştirebilir misiniz? Bir bileşen örneğini yakalamanın ve yanlış olarak kabul edilecek bir yöntemi çağırmanın somut bir örneği nedir?
Danny Libin

2
Ben buna katılıyorum. Bir alanın değerinin doğrulanması veya değiştirilmesi gerekmedikçe / olmadıkça ref kullanıyorum. Değerleri program aracılığıyla değiştirmem veya değiştirmem gerekirse, o zaman durumu kullanırım.
Christopher Davies

1
Ben de buna katılıyorum. Bir keşif aşamasında, çok sayıda girdinin olduğu bir ekrana bilerek saf olarak yaklaştım. İd ile anahtarlanmış bir haritada (durumda) saklanan tüm giriş değerleri. Söylemeye gerek yok, bir onay kutusu tıklaması gibi küçük UI değişikliklerinde durumu ayarlayıp 50'den fazla girdi (bazı malzeme-ui, ağırdı!) Kendi durumunu koruyabilen her girdiyi bileşenlere ayırmak uygun bir yaklaşım gibi görünüyordu. Mutabakata ihtiyaç duyulursa, sadece içine bakın refsve durum değerini alın. Aslında çok güzel bir model gibi görünüyor.
lüks

2
Tamamen katılıyorum. Kabul edilen cevap bence çok belirsiz.
James Wright

Katılıyorum. Genel bir Form bileşeni tasarlarken, bu, kontrollü bileşenlerin sorunlu noktalarını aydınlatır ve odak, hata yönetimi vb. Gerekirse benimle konuşun. Bileşenlerimi referanslara taşıyorum.
kushalvm

6

TL; DR Genel olarak konuşursak, refsReact'in bildirim felsefesine aykırı davranın , bu yüzden onları son çare olarak kullanmalısınız. state / propsMümkün olduğunca kullanın .


Yo kullanımı nerede anlamak için refsvs state / props, tepki tasarım ilkeleri bazı edelim bakmak izler.

React başına dokümantasyon hakkındarefs

Bildirime dayalı olarak yapılabilecek herhangi bir şey için referans kullanmaktan kaçının.

React'in Kaçış Kapaklarıyla İlgili Tasarım İlkeleri

Uygulama oluşturmak için yararlı olan bazı modellerin bildirimsel bir şekilde ifade edilmesi zorsa, bunun için zorunlu bir API sağlayacağız. (ve burada referanslara bağlantı veriyorlar)

Bu, React'in ekibinin reaktif / bildirimsel bir şekilde yapılabilecek her şeyden kaçınmayı refsve bunları kullanmayı önerdiği anlamına gelir state / props.

@Tyler McGinnis de çok güzel bir cevap verdi.

Referansları kullanmanın doğru (ve çok kullanışlı) yolu, onları DOM'dan bir değer elde etmek için kullandığınız zamandır ...

Bunu yapabilseniz de, React'in felsefesine karşı çalışacaksınız. Bir girdide değeriniz varsa, büyük olasılıkla buradan gelir state / props. Kodu tutarlı ve öngörülebilir tutmak için state / propsoraya da bağlı kalmalısınız . refsBazen size daha hızlı çözüm sunduğu gerçeğini kabul ediyorum , bu nedenle bir kavram kanıtı yaparsanız, hızlı ve kirli kabul edilebilir.

Bu, bize birkaç somut kullanım durumu bırakıyor :refs

Odağı, metin seçimini veya medya oynatmayı yönetme. Zorunlu animasyonları tetikliyor. Üçüncü taraf DOM kitaplıklarıyla entegrasyon.


5

Bu gönderi eski.

Bu konudaki küçük deneyimlerimi bir dava hakkında paylaşacağım.

Çok sayıda 'dinamik' giriş ve çok sayıda önbelleğe alınmış veri içeren büyük bir bileşen (414 satır) üzerinde çalışıyordum. (Sayfada yalnız çalışmıyorum ve duyularım bana kodun yapısının muhtemelen daha iyi bölünebileceğini söylüyor, ama mesele bu değil (pekala, olabilir ama ben onunla ilgileniyorum)

İlk olarak, girdilerin değerlerini işlemek için state ile çalıştım:

  const [inputsValues, setInputsValues] = useState([])
  const setInputValue = (id, value) => {
    const arr = [...inputsValues]
    arr[id] = value
    setInputsValues(arr)
  }

ve tabii ki girdilerde:

value={inputsValues[id] || ''}
onChange={event => setInputValue(id, event.target.value)}

Oluşturma o kadar ağırdı ki, giriş değişikliği **** kadar dalgalıydı (tuşu basılı tutmaya çalışmayın, metin yalnızca bir duraklamadan sonra görünecektir)

Referansları kullanarak bundan kaçınabileceğimden emindim.

şu şekilde sona erdi:

  const inputsRef = useRef([])

ve girişlerde:

ref={input => (inputsRef.current[id] = input)}

[Benim durumumda Girdi, Material-UI TextField idi, bu yüzden şuydu:

inputRef={input => (inputsRef.current[id] = input)}

]

Bu sayede yeniden oluşturma yok, girdi düzgün, işlevsellik aynı şekilde çalışıyor. Döngüleri ve hesaplamayı, dolayısıyla enerjiyi de kurtaracak. Dünya için yap x)

Benim sonucum: inputs değeri için useRef değerine ihtiyaç duyulabilir.

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.