Могу я просто добавить; люди всегда предполагают, что это компьютерная проблема, но если вы считаете своими руками (база 10), вы не можете получить (1/3+1/3=2/3)=true
, если у вас нет бесконечности, чтобы добавить 0.333 ... в 0.333 ... так, как и с (1/10+2/10)!==3/10
в базе 2, вы обрезаете ее до 0,333 + 0,333 = 0,666 и, вероятно, округлите ее до 0,677, что также будет технически неточным.
Подсчитайте в тройном, а третья не проблема, может быть, какая-то гонка с 15 пальцами на каждой руке спросит, почему ваша десятичная математика была сломана ...
Что, вероятно, происходит, так это то, что React считает, что между рендерами добавляется только один MyInput
(unemployment-duration
). Таким образом, job-title
никогда не заменяется на unemployment-reason
, и поэтому переопределенные значения меняются местами.
Когда React выполняет diff, он определит, какие компоненты являются новыми и старыми на основе их свойства key
. Если в коде нет такого ключа, он будет генерировать его.
Причина, по которой последний фрагмент кода, который вы предоставляете, работает, потому что React по существу должен изменить иерархию всех элементов в родительском div
, и я считаю, что это вызовет повторную реорганизацию всех детей (именно поэтому это работает). Если бы вы добавили span
внизу, а не в верхнюю часть, иерархия предыдущих элементов не изменилась бы, и эти элементы не будут повторно отображаться (и проблема будет сохраняться).
Вот что говорится в официальной документации React :
Ситуация усложняется, когда дети перетасовываются (как в результатах поиска) или добавляются новые компоненты на перед списком (как в потоках). В тех случаях, когда идентификация и состояние каждого дочернего элемента должны поддерживаться через проходы рендеринга, вы можете однозначно идентифицировать каждого ребенка, назначив ему ключ.
Когда React примиряет детей с ключами, он гарантирует, что любой ребенок с ключом будет переупорядочен (вместо clobbered) или уничтожен (вместо повторного использования).
blockquote>Вы должен иметь возможность исправить это, предоставив уникальный элемент
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> ); } }
OR
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-й пример). Во втором примере diff будет успешным наjob-title
иunemployment-reason
, так как теперь у них разные клавиши.Вы можете, конечно, использовать любые нужные вам клавиши, если они уникальны.
Обновить август 2017
Для лучшего понимания того, как работают клавиши в React, я настоятельно рекомендую прочитать мой ответ на Понимание уникальных ключей в React.js .
Обновление ноября 2017 г.
Это обновление должно было быть опубликовано некоторое время назад, но использование строковых литералов в
ref
теперь устарело. Например, теперьref="job-title"
должен бытьref={(el) => this.jobTitleRef = el}
(например). См. Мой ответ на Предупреждение об изъятии с использованием this.refs для получения дополнительной информации.
Измените ключ компонента.
<Component key="1" />
<Component key="2" />
Компонент будет отключен, и новый экземпляр компонента будет установлен после изменения ключа.
Используйте setState
в вашем представлении, чтобы изменить свойство состояния employed
. Это пример механизма рендеринга React.
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>
);
}
}