max107
@max107

React + Redux. Правильное использование QueryString и componentWillReceiveProps?

Уважаемые коллеги, требуется помощь с вопросом "рекурсивности" redux.

Описание проблемы:
Суть заключается в том, что компонент получает props из react-router и в componentWillMount загружает первую страницу записей. На этом этапе все отлично.
Далее фильтруем / сортируем данные или используем постраничную разбивку и отправляем пользователя на новый url с измененным qs (пример /news/list?page=2). На этом этапе по логике нужно использовать componentWillReceiveProps, так как компонент остался прежним, но пришли новые данные. Если внутри данного метода выполнить dispatch(actions.чтонибудь()), то нам придут данные в props и тут возникает рекурсия.

react-router -> componentWillReceiveProps -> dispatch -> componentWillReceiveProps -> dispatch -> ...


Вопрос:
Каким образом вы используете redux в данных ситуациях и как избежать подобной проблемы?

Дополнительная информация:
Так как возможно я не совсем корректно выразил свои мысли, то попробую перефразировать. В componentWillReceiveProps приходят props переданные из N источника, а так же новое состояние state полученного из redux. В конечном итоге state самого компонента не задействован совсем, а вот в props происходит мешанина.

Чтобы избежать рекурсии когда redux dispatch вызывает сам себя, можно использовать Immutable.js, но мне не кажется это решением проблемы, так как 1) Придется сохранять дополнительный ключ-значение в state 2) Сбрасывать значения в определенный момент. И следить за этим конечно же придется руками.

Еще один вариант который мне кажется тоже не совсем адекватный - проверять все руками:
const { params } = nextProps;
if (params.page != this.props.page || params.page_size != this.props.page_size || params.order != this.props.order || ...) {

Вариант не является адекватным решением при сложных проектах или сложных условиях где параметров участвующих в проверке может быть N, либо они вовсе могут быть динамическими.
  • Вопрос задан
  • 2080 просмотров
Решения вопроса 1
В такой ситуации компонент следует подключить к redux'у через connect. Тогда у вас будет возможность смотреть, что уже загружено, а что нет.

Если у вас какая-то сложная логика - я бы предложил сделать флаг isLoaded и передавать его как props в компонент. Затем, в методе componentWillReceiveProps вы можете проверить, если этот флаг сброшен - вызвать функцию загрузки.

Но конкретно в этом случае лучше поступить так, как сделано в официальном примере real-world-example: проверять изменился-ли номер страницы и только в этом случае диспатчить действия.

UPD1. Пример кода:
// MyComponent
import shallowequal from 'shallowequal';

export default class MyComponent {
  static propTypes = {
    items: PropTypes.array.isRequired,
    filtres: PropTypes.object.isRequired, // <-- тут можно собрать все фильтры
  };

  componentWillReceiveProps(nextProps) {
    if(!shallowequal(this.props.filtres, nextProps.filtres)) {
        loadData(filtres);
    };
  }
}


// MyComponentContainer
import MyComponent from './MyComponent';

function mapState(state, ownProps) {
  return {
    items: applyFiltres(state.someReducer.someItems),
    filtres: ownProps.location.query, // <--- как пример
  };
}

export default connect(mapState)(MyComponent);


В этом случае наш компонент (MyComponent) независим от роутера и от редакса. При этом метод componentWillReceiveProps достаточно простой.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы