Как в react-redux реализовать вызов метода в ответ на изменение стейта?

Есть два компонента: форма авторизации и корзина. У не авторизованного юзера корзина может быть пустой, а у авторизованного там могут быть товары. Соответственно после авторизации хорошо было бы запросить с помощью AJAX корзину и обновить состояние если ее состав отличается.
Использую react-redux с "умными" и "глупыми" компонентами.

После успешной авторизации я передаю action результат и изменяю состояние юзера на user.isAuthorized. Компоненты, которые следят за этим свойством перерендерятся.

Но мне не надо, чтобы корзина перерендеривалась по факту авторизации, нужно сначала сделать AJAX-запрос, а по его результатам уже рендерить корзину.
В компонентах-контроллерах есть только функция connect() со своими функциями-аргументами, которые передают данные в представление. Как-то реагировать на изменения состояния такие компоненты не умеют (я ведь не ошибаюсь в этом?).

Можно, конечно тупо подписаться на изменения user.isAuthorized, но есть два момента, которые меня останавливают:
1. Ее использовать не рекомендуют в гайдах
2. Она будет вызываться на каждый чих по сути вхолостую, в этом случае лучше обернуть ее в Observable и строить на этом все взаимодействия в приложении.

Есть ли какие-то традиционные способы решения этой проблемы?
  • Вопрос задан
  • 1117 просмотров
Решения вопроса 1
maxfarseer
@maxfarseer
https://maxpfrontend.ru, обучаю реакту и компании
Добрый день.

Представим ваш action creator (функцию), которая на success возвращает успешную авторизацию, например:
$.ajax(url...
  success(data) { dispatch({type: AUTH_SUCCESS, data }) })


Кто мешает сделать так?
$.ajax(url...
  success(data) { 
    dispatch({type: AUTH_SUCCESS, data }) 
    loadUserCart(data.user_id) // <- еще один action creator
})

Суть уже понятна? Мы после успешной авторизации юзера, вызываем сразу же следующий экшен-крейтор:
function loadUserCart(id) {
  return (dispatch) => {
    
    dispatch({ type: CART_REQUEST }) // получается, это событие вызовется сразу после успешной авторизации, практически мгновенно

    
    $.ajax(urlForCartUpdate...
      success(data) { 
        dispatch({type: CART_SUCCESS, data })
    })  
  }
}


Далее вы в компоненте с корзиной, настраиваете показ прелоадера, и вуаля! Получается, для юзера, без задержек, как только он авторизовался - у корзины будет крутиться прелоадер. Юзеру все понятно, он занимается своими делами. Как только "данные подъехали" - вы скрыли прелоадер и показали ему необходимые данные по корзине.

нужно сначала сделать AJAX-запрос, а по его результатам уже рендерить корзину

Именно это мы и сделали.

P.S. не знаю, требуется ли это, но на всякий случай укажу, что чтобы сделать прелоадер в шаблоне, вам нужно в редьюсере корзины создать какое-нибудь поле (флаг), например isLoading и устанавливать его в true когда получите action с типом CART_REQUEST, и false для CART_SUCCESS. Таким образом, вы сможете сделать банальный if в шаблоне рендера и показывать либо разметку прелоадера, либо разметук с данными корзины.

=== вторая часть ===
В компонентах-контроллерах есть только функция connect() со своими функциями-аргументами, которые передают данные в представление. Как-то реагировать на изменения состояния такие компоненты не умеют (я ведь не ошибаюсь в этом?).

Еще как умеют, в этом и суть. Вы в mapStateToProps передаете в общем случае:
{
  ваше_название_поля: reduxStore.название_редьюсера
}

В частном случае, может выглядеть так:
function mapStateToProps(state) {
  return {
    rate: state.rate,
  }
}


После того, как вы "подписались" на изменения в state.rate, (а это, если говорить об частном случае, скорее всего reducer с названием rate), ваш "приконекченный" компонент всегда будет получать новые props при изменении в редьюсере. Следовательно, будет вызываться функция render. Само собой - можно хоть сколько "редьюсеров подключить" к одному компоненту.

Имейте ввиду, что все здесь написано для понимания простым русским языком, на самом деле, так как вы используете компонент Provider на самом верхнем уровне вашего приложения, он прокидывает необходимые props вниз. Ваши connect(Компоненты) умеют реагировать на изменение необходимых props => реакт вызывает рендер, так как "пришли новые props".
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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