Передача функции для получения состояния через контейнер - PullRequest
0 голосов
/ 02 мая 2018

У меня есть контейнер, который в настоящее время имеет следующую структуру:

// container.ts
import { connect } from 'react-redux';
import { selectItems } from './actions';
import { selectSelectedItems } from './selectors';
import component from './component';

const mapStateToProps = (state: AppState) => ({
  selected: selectSelectedItems(state),
});

const mapDispatchToProps = {
  select: selectItems,
}

export default connect(mapStateToProps, mapDispatchToProps)(component);

Однако в этом случае каждый экземпляр компонента будет обновляться всякий раз, когда изменяется выбор.

Что мне действительно нужно, так это функция , которая выводит состояние из хранилища с избыточностью , которое может вызываться в определенных обработчиках событий по соображениям производительности. Например, мне нужно условно открыть модал, если они выпадают с выбранными элементами. Это будет реализовано так.

onDrop = () => {
  // if there are any selected at all,
  // open a modal for the user.
  const selected = this.props.getSelected();
  if (selected.length) {
    this.openMoveRequestModal();
  }
}

Я могу заставить его «работать» довольно уродливым методом.

export default class ProductGrid extends React.PureComponent<Props> {
  static contextTypes = { store: PropTypes.object };

  onDrop = () => {
    const state = this.context.store.getState();
    // do whatever here
  }
}

Но в идеале , я бы просто смог пройти через ссылку на функцию, которая получала бы состояние из моего хранилища редуксов.

Можно ли передать функцию, которая выводит состояние через контейнер react-redux?

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

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

export default class ProductGrid extends React.PureComponent {
  static propTypes = {
    selected: PropTypes.array.isRequired,
    /* others... */
  }

  shouldComponentUpdate (nextProps, nextState) {
    // If any props other than "selected" changed, re-render.
    // Otherwise, if no props or only "selected" changed, skip the render.
    const changedProps = getChangedProps(this.props, nextProps)
    changedProps.delete('selected')
    return changedProps.size > 0
  } 
}

function getChangedProps (currentProps, nextProps) {
  return new Set(
    Object.keys(currentProps)
      .filter(propName => currentProps[propName] !== nextProps[propName])
  )
}

shouldComponentUpdate - это механизм, позволяющий избежать повторного рендеринга на основе некоторого условия (свойство реквизита и состояния). Если функция возвращает false, компонент не будет отображаться, пока не получит новый реквизит или состояние - в этот момент shouldComponentUpdate будет вызван снова.

Производительность важна при реализации shouldComponentUpdate, потому что она вызывается при каждом потенциальном рендере (т. Е. Всякий раз, когда изменяется реквизит или состояние).

0 голосов
/ 02 мая 2018

Компоненты обычно не имеют доступа ко всему состоянию магазина, потому что это плохо сказывается на производительности. Если вы вернете все состояние хранилища из функции mapState, компонент будет выполнять повторную визуализацию при каждом отправленном действии, а не только тогда, когда данные, в которых он действительно нуждается, изменяются.

Таким образом, если вашему компоненту необходим доступ к отдельному фрагменту состояния для принятия дополнительных решений, у вас есть два основных варианта:

  • Извлеките эту дополнительную часть информации и верните ее в mapState вместе с данными, которые компонент фактически должен отобразить
  • Переместите эту логику в функцию thunk, которая имеет доступ к getState.

Я рекомендую использовать thunk.

Пример:

function openModalIfSelected() {
    return (dispatch, getState) => {
        const state = getState();

        const selected = selectSelectedItems(state);

        if(selected.length) {
            dispatch(openMoveRequestModal());
        }
    }
}

// later, in the component file

const actionCreators = {openModalIfSelected};

class ProductGrid extends Component {
    render() {
        return (
            <div>
                {/* all the normal rendering stuff here */}
                <DropTarget onDrop={this.props.openModalIfSelected} />
            </div>
        );
    }
}

export default connect(null, actionCreators)(ProductGrid);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...