Ответ 1
Вероятно, происходит то, что React считает, что между MyInput
только один MyInput
(unemployment-duration
). Таким образом, название job-title
никогда не заменяется unemployment-reason
, поэтому предопределенные значения меняются местами.
Когда React выполняет diff, он определяет, какие компоненты являются новыми, а какие - старыми, на основании их key
свойства. Если в коде нет такого ключа, он сгенерирует свой собственный.
Причина, по которой последний предоставленный вами фрагмент кода работает, заключается в том, что React, по сути, необходимо изменить иерархию всех элементов в родительском div
и я считаю, что это вызовет повторную визуализацию всех дочерних элементов (именно поэтому он работает). Если бы вы добавили span
внизу, а не вверху, иерархия предыдущих элементов не изменилась бы, и эти элементы не перерисовались бы (и проблема не исчезла бы).
Вот что говорится в официальной документации React:
Ситуация усложняется, когда дочерние элементы перемешиваются (как в результатах поиска) или если новые компоненты добавляются в начало списка (как в потоках). В этих случаях, когда идентичность и состояние каждого дочернего элемента должны поддерживаться на всех этапах рендеринга, вы можете уникально идентифицировать каждого дочернего элемента, назначив ему ключ.
Когда React примирит ключевые дочерние элементы, он будет гарантировать, что любой дочерний элемент с ключом будет переупорядочен (вместо того, чтобы перекрываться) или уничтожен (вместо повторного использования).
Вы сможете исправить это, предоставив уникальный key
элемент самостоятельно родительскому элементу div
или всем элементам MyInput
.
Например:
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>
);
}
}
ИЛИ ЖЕ
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>
);
}
}
Теперь, когда React выполнит diff, он увидит, что divs
отличается, и повторно отобразит его, включая все его дочерние элементы (1-й пример). Во втором примере разница будет успешной по job-title
и unemployment-reason
поскольку теперь у них разные ключи.
Конечно, вы можете использовать любые ключи, если они уникальны.
Обновление август 2017
Чтобы лучше понять, как ключи работают в React, я настоятельно рекомендую прочитать мой ответ на Понимание уникальных ключей в React.js.
Обновление ноябрь 2017
Это обновление должно было быть опубликовано некоторое время назад, но использование строковых литералов в ref
теперь не рекомендуется. Например, вместо ref="job-title"
теперь должно быть ref={(el) => this.jobTitleRef = el}
(например). Смотрите мой ответ на предупреждение об устаревании, используя this.refs для получения дополнительной информации.