Запретить повторный рендеринг, когда элемент React передан как свойство

В моем приложении React я использую несколько библиотек (например, Material UI и React Intl) для передачи элементов React в качестве свойств от компонентов более высокого уровня к «тупым компонентам», у которых одна задача: рендеринг.

Умный компонент:

import ActionExplore from 'material-ui/svg-icons/action/explore';
import { FormattedMessage } from 'react-intl';

export class SmartComponent extends Component {
  render() {
    return (
      <div>
        <DumbComponent
          text={<FormattedMessage id="en.dumbComponent.text" />}
          icon={<ActionExplore/>}
        />
        <AnotherDumbComponent {props.that.are.changing} />
      </div>
    );
  }
}

Тупой компонент:

import shallowCompare from 'react-addons-shallow-compare';

export class DumbComponent extends Component {
  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
  }

  render() {
    return (
      <div>
        <h1>{this.props.text}</h1>
        {this.props.icon}
      </div>
    );
  }
}

Преимущество этого заключается в том, что DumbComponent не нужно ничего знать о логике приложения (пользовательский интерфейс материала, интернационализация и т. Д.). Он просто отображает, оставляя SmartComponent заботиться обо всей бизнес-логике.

Обратной стороной этого подхода является производительность: DumbComponent будет всегда повторно отрисовываться, даже когда свойства AnotherDumbComponent меняются вместо его собственных, потому что shouldComponentUpdate always возвращает true. shouldComponentUpdate не может точно проверить равенство между элементами React в приведенном выше примере.

Как можно проверить равенство элементов React в shouldComponentUpdate? Это слишком дорого? Является ли передача элементов React в качестве опоры тупым компонентам - плохой идеей? Можно ли не передавать элементы React в качестве свойств, но при этом сохранять компоненты бессмысленными? Спасибо!


person Jon Cursi    schedule 06.06.2016    source источник
comment
Вам просто нужно убедиться, что он shouldComponentUpdate возвращает false, если вы не хотите повторно выполнять рендеринг. Если это достаточно просто, почему бы не создать свою собственную логику? Например: if (this.props.text !== nextProps.text || this.props.icon !== nextProps.icon) return true; return false;.   -  person Yuya    schedule 06.06.2016
comment
Не могли бы вы добавить пример того, как вы меняете свой реквизит? Потому что вы не гарантируете, что проверка равенства неизменяемости всегда будет возвращать истину, даже для одних и тех же данных.   -  person Pierre Criulanscy    schedule 07.06.2016


Ответы (2)


Будет ли это производительным или нет, будет зависеть от вашего варианта использования. Как правило, я думаю, что этот вид логики лучше всего использовать, когда вы ожидаете, что ввод пользователя будет влиять только на дочерние элементы «немого компонента», а не на его сверстников.

Например, диалоговое окно Material-UI имеет почти идентичную структуру с тем, что вы предлагаете для его кнопок действий и заголовка. (https://github.com/callemall/material-ui/blob/master/src/Dialog/Dialog.js#L292). Но в этом случае он работает хорошо, потому что эти элементы находятся в модальном окне, которое само по себе не изменяется, если вы его не открываете или не закрываете.

Что, если бы вы передали объекты, необходимые для создания дочерних элементов, без передачи всего элемента в качестве еще одного возможного обходного пути? Я не пробовал это делать, поэтому не уверен, насколько хорошо это будет работать, но, возможно, стоит попробовать. Что-то до степени;

<DumbComponent 
    textComponent={FormattedMessage} 
    textProps={{id: "en.dumbComponent.text"}}/>

//In DumbComponent;

render(){
    return (
        <div>
            <h1>
                <this.props.textComponent {...this.props.textProps}/>
            </h1>

        </div>
    );
}

Может дать вам несколько более конкретных вещей, с которыми можно поиграть, когда вы решите, стоит ли вам обновляться или нет.

person Jake Haller-Roby    schedule 06.06.2016

Я решил это, преобразовав эти простые элементы React в карты Immutable.js и вместо этого передав их в качестве свойств.

Эта статья была очень полезной: https://www.toptal.com/react/react-redux-and-immutablejs

Immutable.js позволяет нам обнаруживать изменения в объектах / массивах JavaScript, не прибегая к неэффективности глубоких проверок равенства, что, в свою очередь, позволяет React избегать дорогостоящих операций повторного рендеринга, когда они не требуются.

person Jon Cursi    schedule 07.06.2016