React bileşenlerine yeniden bağlanmaya nasıl zorlanır?


104

Koşullu işlemeye sahip bir görünüm bileşenim olduğunu varsayalım:

render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

Girdiğim şuna benzer:

class MyInput extends React.Component {

    ...

    render(){
        return (
            <div>
                <input name={this.props.name} 
                    ref="input" 
                    type="text" 
                    value={this.props.value || null}
                    onBlur={this.handleBlur.bind(this)}
                    onChange={this.handleTyping.bind(this)} />
            </div>
        );
    }
}

employedDoğru olduğunu söyleyelim . Onu yanlış olarak değiştirdiğimde ve diğer görünüm işlediğinde, yalnızca unemployment-durationyeniden başlatılıyor. Ayrıca unemployment-reason, değeriyle önceden doldurulur job-title(koşul değişmeden önce bir değer verilmişse).

İkinci oluşturma rutinindeki işaretlemeyi şöyle değiştirirsem:

render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <span>Diff me!</span>
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

Görünüşe göre her şey yolunda gidiyor. Görünüşe göre React, "iş unvanı" ve "işsizlik nedeni" ni ayırt edemiyor.

Lütfen bana neyi yanlış yaptığımı söyle ...


1
Geçişten önceki ve sonraki öğelerin data-reactidher birinde MyInput(veya inputDOM'da görüldüğü gibi) neler var employed?
Chris

@Chris MyInput bileşeninin girdiyi bir <div>. data-reactidNitelikleri sarma div ile giriş alanı hem farklı gibi görünüyor. job-titlegiriş id alır data-reactid=".0.1.1.0.1.0.1", unemployment-reasongiriş id alırdata-reactid=".0.1.1.0.1.2.1"
o01

1
peki ya unemployment-duration?
Chris

@Chris Üzgünüm, çok erken konuştum. İlk örnekte ("diff me" aralığı olmadan) reactidnitelikler aynıdır job-titleve unemployment-reasonikinci örnekte (diff aralığı ile) farklıdır.
o01

İçin @Chris özelliğin daima tektir. unemployment-durationreactid
o01

Yanıtlar:


109

Muhtemelen olan şey, React'in renderlar arasına yalnızca bir MyInput( unemployment-duration) eklendiğini düşünmesidir . Bu nedenle, job-titleasla ile değiştirilmez unemployment-reason, bu da önceden tanımlanmış değerlerin değiştirilmesinin nedenidir.

React farkı yaptığında, özelliklerine göre hangi bileşenlerin yeni ve hangilerinin eski olduğunu belirleyecektir key. Kodda böyle bir anahtar yoksa, kendi anahtarını oluşturacaktır.

Sağladığınız son kod parçacığının çalışmasının nedeni, React'in esasen ana öğenin altındaki tüm öğelerin hiyerarşisini değiştirmesi gerektiğidir ve bunun tüm alt öğelerin divyeniden oluşturulmasını tetikleyeceğine inanıyorum (bu yüzden çalışıyor). Eğer ilave olsaydı spantepe yerine, önceki unsurları olmaz değişim hiyerarşisine ve bu eleman en-işlemek yeniden olmaz (ve sorun devam ediyorum).

Resmi React belgelerinin söylediği şu:

Çocuklar karıştırıldığında (arama sonuçlarında olduğu gibi) veya listenin önüne yeni bileşenler eklendiğinde (akışlarda olduğu gibi) durum daha karmaşık hale gelir. Oluşturma geçişlerinde her bir çocuğun kimliğinin ve durumunun korunması gereken bu durumlarda, her çocuğu bir anahtar atayarak benzersiz şekilde tanımlayabilirsiniz.

React, anahtarlı çocukları uzlaştırdığında, anahtara sahip herhangi bir çocuğun yeniden sıralanmasını (yuhalanmak yerine) veya yok edilmesini (yeniden kullanmak yerine) garanti eder.

keyÜst öğeye divveya tüm MyInputöğelere kendiniz benzersiz bir öğe sağlayarak bunu düzeltebilmelisiniz .

Örneğin:

render(){
    if (this.state.employed) {
        return (
            <div key="employed">
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div key="notEmployed">
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

VEYA

render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput key="title" ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <MyInput key="reason" ref="unemployment-reason" name="unemployment-reason" />
                <MyInput key="duration" ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

Şimdi, React farkı yaptığında, divsfarklı olduğunu görecek ve tüm alt öğeleri dahil olmak üzere onu yeniden işleyecektir (1. örnek). 2. örnekte, fark başarılı olacaktır job-titleve unemployment-reasonartık farklı anahtarlara sahipler.

Elbette, benzersiz oldukları sürece istediğiniz herhangi bir anahtarı kullanabilirsiniz.


Ağustos 2017 Güncellemesi

React'te anahtarların nasıl çalıştığına dair daha iyi bir kavrayış için React.js'deki Benzersiz anahtarları anlama konusundaki yanıtımı okumanızı şiddetle tavsiye ederim .


Kasım 2017 güncellemesi

Bu güncelleme bir süre önce gönderilmiş olmalıydı, ancak dizide değişmez değerleri kullanmak refartık kullanımdan kaldırıldı. Örneğin ref="job-title", şimdi bunun yerine ref={(el) => this.jobTitleRef = el}(örneğin) olmalıdır. Daha fazla bilgi için this.refs'i kullanarak Kullanımdan kaldırma uyarısına verdiğim yanıta bakın .


10
it will determine which components are new and which are old based on their key property.- bu ... anahtar ... anlayışım için
Larry

1
Çok teşekkür ederim ! Ayrıca bir haritadaki tüm çocuk bileşenlerinin başarıyla yeniden işlendiğini anladım ve nedenini anlayamadım.
ValentinVoilean

güzel bir ipucu, div için anahtar olarak bir durum değişkeni (örneğin, bir id gibi değişir) kullanmaktır!
Macilias

203

Bileşenin anahtarını değiştirin.

<Component key="1" />
<Component key="2" />

Anahtar değiştiğinden, bileşenin bağlantısı kesilecek ve Bileşenin yeni bir örneği eklenecektir.

düzenleme : Belgelendirilmiş Muhtemelen Türetilmiş Duruma İhtiyacınız Yok :

Bir anahtar değiştiğinde, React mevcut olanı güncellemek yerine yeni bir bileşen örneği oluşturacaktır. Anahtarlar genellikle dinamik listeler için kullanılır, ancak burada da kullanışlıdır.


46
Bu, React belgelerinde çok daha açık olmalıdır. Bu tam olarak peşinde olduğum şeyi başardı, ancak bulmam saatler sürdü.
Paul

4
Bu bana çok yardımcı oldu! Teşekkürler! Bir CSS animasyonunu sıfırlamam gerekiyordu, ancak bunu yapmanın tek yolu yeniden oluşturmaya zorlamaktı. Bunun react belgelerinde daha açık olması gerektiğine katılıyorum
Alex. S.

@ Alex.P. Güzel! CSS animasyonları bazen yanıltıcı olabilir. Bir örnek görmek isterim.
Alex K

1
Bu tekniği açıklayan React dokümantasyonu: reactjs.org/blog/2018/06/07/…
GameSalutes

Teşekkür ederim. Bunun için çok minnettarım. Rastgele sayıları "randomNumber" gibi bildirilmemiş nesnelere beslemeyi denedim, ancak işe yarayan tek destek anahtardı.
ShameWare

5

Durumun özelliğini setStatedeğiştirmek için kendi görünümünüzde kullanın employed. Bu, React oluşturma motorunun bir örneğidir.

 someFunctionWhichChangeParamEmployed(isEmployed) {
      this.setState({
          employed: isEmployed
      });
 }

 getInitialState() {
      return {
          employed: true
      }
 },

 render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <span>Diff me!</span>
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

Bunu zaten yapıyorum. 'Kullanılan' değişken, görünüm bileşenleri durumunun bir parçasıdır ve setState işlevi aracılığıyla değiştirilir. Bunu açıklamadığım için üzgünüm.
o01

"çalışan" değişken, React durumunun özelliği olmalıdır. Kod örneğinizde açık değil.
Dmitriy

this.state.employed nasıl değiştirilir? Kodu gösterin lütfen. SetState'i kodunuzda doğru yerde kullandığınızdan emin misiniz?
Dmitriy

Görünüm bileşeni, örneğimin gösterdiğinden biraz daha karmaşık. MyInput bileşenlerine ek olarak, bir onChange işleyicisiyle 'çalıştırılan' değerini kontrol eden bir radyo düğmesi grubu oluşturur. OnChange işleyicisinde, görünüm bileşeninin durumunu buna göre ayarlıyorum. Radyobutton grubunun değeri değiştiğinde görünüm yeniden iyi işlenir, ancak React ilk MyInput bileşeninin daha önce "kullanılan" değiştiğini düşünür.
o01

0

Uygulamam için Crud üzerinde çalışıyorum. Bağımlılığım olarak Reactstrap aldım.

import React, { useState, setState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import firebase from 'firebase';
// import { LifeCrud } from '../CRUD/Crud';
import { Row, Card, Col, Button } from 'reactstrap';
import InsuranceActionInput from '../CRUD/InsuranceActionInput';

const LifeActionCreate = () => {
  let [newLifeActionLabel, setNewLifeActionLabel] = React.useState();

  const onCreate = e => {
    const db = firebase.firestore();

    db.collection('actions').add({
      label: newLifeActionLabel
    });
    alert('New Life Insurance Added');
    setNewLifeActionLabel('');
  };

  return (
    <Card style={{ padding: '15px' }}>
      <form onSubmit={onCreate}>
        <label>Name</label>
        <input
          value={newLifeActionLabel}
          onChange={e => {
            setNewLifeActionLabel(e.target.value);
          }}
          placeholder={'Name'}
        />

        <Button onClick={onCreate}>Create</Button>
      </form>
    </Card>
  );
};

Orada bazı React Hook'ları var


SO'ya hoş geldiniz! İyi bir cevabın nasıl yazılacağını gözden geçirmek isteyebilirsiniz . Sadece kodu göndermenin ötesinde soruyu nasıl çözdüğünüze biraz açıklama ekleyin.
displacedtexan
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.