Сохранение исходного состояния элементов React DOM во время трансплантации
Я работаю с React, чтобы создать подобный форме интерфейс, вы знаете, с различными <input/>
элементы и тому подобное. Одна из особенностей заключается в том, что текстовые поля упорядочиваются и перестраиваются из-за других данных (с сервера или других входных данных)...
React хорошо справляется со всеми изменениями, за исключением одного случая: перемещение элемента между родителями.
мой render()
JSX может переключаться между следующими в зависимости от состояния:
return (
<div className="parent">
<h4>Before container</h4>
<input type="text" key="one"/>
<div className="container"/>
</div>
)
А также:
return (
<div className="parent">
<h4>After container</h4>
<div className="container"/>
<input type="text" key="one"/>
</div>
)
Это все работает просто отлично - ввод перемещается и сохраняет все свое родное состояние браузера (фокус / введенный в настоящее время текст / выделение / и т. Д.).
Но когда он переключается на:
return (
<div className="parent">
<h4>Inside container</h4>
<div className="container">
<input type="text" key="one"/>
</div>
</div>
)
Это воссоздает <input/>
Элемент DOM с нуля и все его нативное состояние браузера теряется, несмотря на сохранение key=
нетронутый!
Вот кодекс, демонстрирующий, что идет не так. Ваш набор текста остается неизменным, перемещаясь между "до" и "после", но умирает "внутри".
Является ли это фундаментальным ограничением React или существует правильный способ сохранить нативный элемент в целости при перемещении между родителями?
2 ответа
key
prop предназначен для разграничения между равноправными компонентами. Предполагается, что компоненты в разных контекстах не сопоставимы. Например,
<div className="parent">
<h4>Before and After container</h4>
<input type="text" key="one"/>
<div className="container"/>
<input type="text" key="one"/>
</div>
Вызовет проблемы, но;
<div className="parent">
<h4>Before and Inside container</h4>
<input type="text" key="one"/>
<div className="container">
<input type="text" key="one"/>
</div>
</div>
будет хорошо.
Итак, как мы решаем проблему?
Лучше всего назначить ссылку на поле ввода, а затем перефокусировать ее после каждого обновления;
<input type="text" key="one" ref={(input) => { this.textInput = input; }}/>
а потом
componentDidUpdate() {
this.textInput.focus();
}
обновленная кодовая ручка: https://codepen.io/anon/pen/eGdmeV
РЕДАКТИРОВАТЬ:
Принимая во внимание, что вам действительно нужна встроенная поддержка из-за других ваших инструментов, лучшим способом может быть просто обеспечить согласованную иерархию;
<div className="parent">
<h4>Before container</h4>
<div key="oneContainer">
<input type="text" key="one"/>
</div>
<div className="container"/>
</div>
<div className="parent">
<h4>After container</h4>
<div className="container"/>
<div key="oneContainer">
<input type="text" key="one"/>
</div>
</div>
<div className="parent">
<h4>Inside container</h4>
<div className="container" key="oneContainer">
<input type="text" key="one"/>
</div>
</div>
Codepen: https://codepen.io/anon/pen/bowNKB
Ваше наблюдение верно, когда вы помещаете элемент ввода в новый контейнер, реагирует, создает новый виртуальный узел DOM и повторно отображает его дочерние элементы. Когда вы просто размещаете группу элементов на одной и той же глубине, реагирование отслеживает порядок каждого элемента на основе ключевого элемента и только переупорядочивает элемент без полного повторного отображения. Хотя я понятия не имею, почему вы хотите поместить элемент в контейнер при повторном кодировании, вы можете сохранить состояние в состоянии компонента и передать его соответствующим образом. Если состояние как-то не может быть сохранено в состояние. Вы должны найти общую иерархию для элементов, например, обернуть каждый вход в контейнере и назначить ключ для контейнеров вместо входов.