Избегайте повторного отображения при каждом событии изменения в React - PullRequest
0 голосов
/ 26 апреля 2019

Я работаю над существующим кодом React, который кто-то написал, и сталкиваюсь с некоторыми проблемами с производительностью в нем. Рассмотрим следующий фрагмент кода:

//ComponentA.js
class ComponentA extends React.Component {
    this.state = { someValue : 'dummy' }
    // Other code

    // We are using Babel, so class fields are OK
    updateVal = e => this.setState({ someValue : e.target.value})
    // fetchData makes an ajax call
    fetchData = () => { fetch(this.state.someValue) }
    render() {
       return (
         <ComponentB val={this.state.someValue} 
                     updateVal={this.updateVal}
                     fetchData={this.fetchData}/>
       )
}

//ComponentB.js
class ComponentB extends React.Component {
    render() {
      return (    
        // Other code

        //Input is a component from a library
        <Input onChange={(e) => { this.updateValue(e) } } 
               onBlur={this.props.fetchData} />
               value={this.props.val}
      )
    }
}

Теперь проблема в том, что всякий раз, когда пользователь вводит Input, значение печатается через несколько секунд. Это потому, что ComponentA на самом деле является довольно большим компонентом (я знаю, что это плохо, но я не хочу его реорганизовывать сейчас, потому что он огромен, и у нас не так много времени), и он перерисовывается каждый раз, когда пользователь вводит. Чтобы избежать этого, я могу сделать Input неконтролируемым компонентом и обновить ComponentA someValue onBlur. Другой способ - получить initialState in ComponentB, равный val prop. И onChange, this.setState вызывается только для ComponentB. Тогда onBlur, я могу обновить ComponentA this.state.someValue.

Однако в обоих этих подходах принцип single source of truth Реакта потерян. Так что будет лучшим решением в этом случае?

Здесь я также хотел бы спросить, что вредного в использовании неконтролируемого компонента здесь?

Ответы [ 2 ]

0 голосов
/ 26 апреля 2019

Рендеринг оптимизирован (я не думаю, что проблема связана с размером компонента).Я думаю, что проблема вызвана не вашей структурой (это то, что рекомендуется самой React), а компонентом Input, взятым из библиотеки.

Вы также можете сохранить состояние в ComponentB и предоставить функцию дляполучить / установить значения, но тогда, как вы сказали, вы потеряете single source of trouth, но вы будете избегать повторного рендеринга при каждом изменении ввода.

Надеюсь, это поможет!

0 голосов
/ 26 апреля 2019

Быстрое исправление может заключаться в том, чтобы отменить обработчик onChange.

Я обычно использую debounce от Lodash, но вы можете использовать другой или написать свою собственную версию.

import { debounce } from 'lodash'

class ComponentB extends React.Component {

    // componentA will rerender only every 300ms instead of every time user types
    handleChange = debounce(e => this.props.updateVal(e), 300)

    render() {
      return <Input onChange={this.handleChange} value={this.props.val} />
    }

}

Лучшим решением было бы разделение / рефакторинг componentA.

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