Изменить реагировать реквизиты в компоненте в качестве оптимизации - PullRequest
0 голосов
/ 05 октября 2018

Проблема

* Это не совсем мой случай, но вот что имеет значение.
Представьте себе приложение, которое отображает список элементов:

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)} }

Это решение кажется слишком неудобным для реализации.Также это медленно по сравнению с альтернативами ниже.События, происходящие при изменении ввода (поправьте меня, если я ошибаюсь):

  1. уведомляет родительский компонент об изменении через цепочку компонентов
  2. родительский компонент создает массив новых элементов и вызывает setState
  3. обновляется весь виртуальный DOM (включая каждый элемент)
  4. обновленный виртуальный DOM сравнивается с предыдущей версией виртуального DOM
  5. один элемент обновляется в реальном DOM

2.Обновите реквизиты элемента напрямую и forceUpdate()

  • переименуйте элемент в класс вместо функционального компонента
  • в элементе: onChange = {evt => {element.text = evt.целевое значение;this.forceUpdate ()}}

События, происходящие при изменении ввода:

  1. props.element.text изменен и forceUpdate называется
  2. обновляется только один элемент в виртуальном DOM
  3. обновленное поддерево виртуального DOM (один элемент) сравнивается со старым виртуальным DOM
  4. один элемент обновляется в реальном DOM

Вопросы

В настоящее время я использую промежуточный подход, но больше на стороне «правильного реагирования».И это не достаточно быстро.
Мне нравится второй вариант больше, он требует меньше кода и кажется, что он должен работать намного быстрее (теоретически).

  1. У меня получится значительно лучше производительностьиспользуя второй подход?(Помните, что существует множество элементов)
  2. К каким конкретным проблемам может привести этот подход?Да, да, я знаю, что код менее прозрачен, и это не так, как должно быть.
  3. Видите ли вы какой-либо другой способ повысить производительность?Я был бы рад попробовать еще меньше предложений, подобных реакциям, возможно, стоит отказаться от реакции частично или полностью.

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

вы можете сделать вот так

 this.state = {elements: [
  {id: 1, text: 'apple'},
   {id: 23, text: 'banana'},
   ]}

   // creating a update function which you will pass down to the child

    updateState = (id, val) => {
           const newElements = this.state.elements;
            newElements.map(item => {
               if(item.id === id) item.text = val;
             });
          this.setState({
           elements: newElements,
          })
       }
 render() { ... <ElementsList elements={this.state.elements} updateState ={this.updateState}/> ... }

теперь в ElementsList

       const ElementsList = ({elements, updateState,  <onElementTextChange>}) => (
       <div className='ElementsList'>
        {elements.map(el => (
       <Element
        key={el.id}
        element={el}
        updateState = {updateState}
         />
        ))}
        </div>
         )

теперь в элементе

    export class Element extends React.Component{

     state = {
       value: '',  
       }
         onChangeValue = (e) => { 
              this.setState({ value: e.target.value});
            // calling the parent function directly
               this.props.updateState(this.props.element.id, e.target.value);
            }
       componentDidMount(){
         this.setState({
         value: this.props.element.text,
       })
         }
      render(){
        return(
              <div className='Element'>
       <div className='element-text'>{element.text}</div>
       <input type='text' value={this.state.value} onChange={this.onChangeValue}></input>
       </div>
        )
        }
       } 
0 голосов
/ 05 октября 2018

Неизменяемые структуры данных решают ваши проблемы с производительностью с помощью таких методов, как запоминание и совместное использование структур.

Вам следует использовать Immutable.js .Затем вы можете использовать React.PureComponent для эффективной проверки равенства значений для больших структур данных.

Одним недостатком является то, что структуры данных Immutable.js плохо сочетаются с обычными изменяемыми структурами данных JavaScript,что может быть неприятно.Некоторые языки, такие как Elm или ClojureScript, предлагают первоклассную поддержку для таких структур данных, что делает их намного более согласованными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...