Проблема
* Это не совсем мой случай, но вот что имеет значение.
Представьте себе приложение, которое отображает список элементов:
const ElementsList = ({elements, <onElementTextChange>}) => (
<div className='ElementsList'>
{elements.map(el => (
<Element
key={el.id}
element={el}
/>
))}
</div>
)
Элементы находятся в состоянииродительского компонента, который отображает ElementsList
.Каждый элемент представляет собой простой объект:
this.state = {elements: [
{id: 1, text: 'apple'},
{id: 23, text: 'banana'},
]}
...
render() { ... <ElementsList elements={this.state.elements}/> ... }
Каждый элемент визуализируется рядом с полем ввода, чтобы изменить его текст:
export const Element = ({element, <onTextChange>}) => (
<div className='Element'>
<div className='element-text'>{element.text}</div>
<input type='text' value={element.text} onChange={???}></input>
</div>
)
Учтите, что элементов может быть много (чем большеприложение может обрабатывать данные).
Теперь вопрос заключается в том, как мы должны обновлять тексты с помощью этих входных данных.
Решения
Я вижу 2 варианта (некоторые комбинацииони возможны):
1.Правильный способ реагирования (не так ли?) - уведомить родительский компонент об изменении
- в элементе:
onChange={evt => onTextChange(evt.target.value)}
- в ElementsList:
onTextChange={newText => onElementTextChange(el, newText)}
- в родительском элементекомпонент:
onElementTextChange={ (element, newText) => {make new elements array with the updated element somehow; setState(elements)} }
Это решение кажется слишком неудобным для реализации.Также это медленно по сравнению с альтернативами ниже.События, происходящие при изменении ввода (поправьте меня, если я ошибаюсь):
- уведомляет родительский компонент об изменении через цепочку компонентов
- родительский компонент создает массив новых элементов и вызывает
setState
- обновляется весь виртуальный DOM (включая каждый элемент)
- обновленный виртуальный DOM сравнивается с предыдущей версией виртуального DOM
- один элемент обновляется в реальном DOM
2.Обновите реквизиты элемента напрямую и forceUpdate()
- переименуйте элемент в класс вместо функционального компонента
- в элементе: onChange = {evt => {element.text = evt.целевое значение;this.forceUpdate ()}}
События, происходящие при изменении ввода:
- props.element.text изменен и
forceUpdate
называется - обновляется только один элемент в виртуальном DOM
- обновленное поддерево виртуального DOM (один элемент) сравнивается со старым виртуальным DOM
- один элемент обновляется в реальном DOM
Вопросы
В настоящее время я использую промежуточный подход, но больше на стороне «правильного реагирования».И это не достаточно быстро.
Мне нравится второй вариант больше, он требует меньше кода и кажется, что он должен работать намного быстрее (теоретически).
- У меня получится значительно лучше производительностьиспользуя второй подход?(Помните, что существует множество элементов)
- К каким конкретным проблемам может привести этот подход?Да, да, я знаю, что код менее прозрачен, и это не так, как должно быть.
- Видите ли вы какой-либо другой способ повысить производительность?Я был бы рад попробовать еще меньше предложений, подобных реакциям, возможно, стоит отказаться от реакции частично или полностью.