Допустим, у меня есть компонент представления с условной визуализацией:
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>
);
}
}
MyInput выглядит примерно так:
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>
);
}
}
Скажем employed
так. Всякий раз, когда я переключаю его на false и другое представление отображается, только unemployment-duration
повторно инициализируется. Также unemployment-reason
предварительно заполняется значением из job-title
(если значение было задано до изменения условия).
Если я изменю разметку во второй процедуре рендеринга на что-то вроде этого:
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>
);
}
}
Вроде все нормально работает. Похоже, React просто не умеет различать «должность» и «причину безработицы».
Подскажите пожалуйста, что я делаю не так ...
data-reactid
на каждом изMyInput
(илиinput
, как видно в DOM) элементах до и послеemployed
переключения?<div>
. Этиdata-reactid
атрибуты , как представляется, отличается как на оберточной DIV и поле ввода.job-title
input получает идентификаторdata-reactid=".0.1.1.0.1.0.1"
, аunemployment-reason
input получает идентификаторdata-reactid=".0.1.1.0.1.2.1"
unemployment-duration
?reactid
атрибуты одинаковы поjob-title
иunemployment-reason
, в то время как во втором примере (с пролетом дифф) они отличаются.unemployment-duration
вreactid
атрибуте всегда уникален.Ответы:
Что, вероятно, происходит, так это то, что React считает, что между рендерами добавляется только один
MyInput
(unemployment-duration
). Таким образом,job-title
никогда не заменяется наunemployment-reason
, поэтому также меняются местами предопределенные значения.Когда React выполняет сравнение, он определяет, какие компоненты новые, а какие старые, на основе их
key
свойств. Если в коде такого ключа нет, он сгенерирует свой собственный.Причина, по которой последний предоставленный вами фрагмент кода работает, заключается в том, что React по существу должен изменить иерархию всех элементов в родительском элементе,
div
и я считаю, что это вызовет повторный рендеринг всех дочерних элементов (вот почему он работает). Если бы вы добавилиspan
элемент внизу, а не вверху, иерархия предыдущих элементов не изменилась бы, и эти элементы не перерисовывались бы (и проблема не исчезла бы).Вот что говорится в официальной документации React :
Вы должны иметь возможность исправить это, предоставив уникальный
key
элемент самому родительскому элементуdiv
или всемMyInput
элементам.Например:
ИЛИ
Теперь, когда React выполнит сравнение, он увидит, что
divs
они разные, и повторно отобразит его, включая всех своих дочерних элементов (1-й пример). Во 2 - ом примере, разница будет иметь успех наjob-title
иunemployment-reason
так как они теперь имеют разные ключи.Конечно, вы можете использовать любые ключи, если они уникальны.
Обновление август 2017 г.
Чтобы лучше понять, как работают ключи в React, я настоятельно рекомендую прочитать мой ответ на тему «Понимание уникальных ключей в React.js» .
Обновление ноябрь 2017 г.
Это обновление должно было быть опубликовано некоторое время назад, но
ref
теперь использование строковых литералов в нем не рекомендуется. Например,ref="job-title"
теперь должно бытьref={(el) => this.jobTitleRef = el}
(например). См. Мой ответ на предупреждение об устаревании с помощью this.refs для получения дополнительной информации.источник
it will determine which components are new and which are old based on their key property.
- это было ... ключом ... к моему пониманиюИзмените ключ компонента.
Компонент будет размонтирован, и новый экземпляр Компонента будет смонтирован, так как ключ изменился.
изменить : Документировано, что вам, вероятно, не нужно производное состояние :
источник
Используйте
setState
в своем представлении, чтобы изменитьemployed
свойство состояния. Это пример движка рендеринга React.источник
Я работаю над Crud для своего приложения. Вот как я это сделал. Получил Reactstrap в качестве зависимости.
Некоторые React Hooks там
источник