> For the complete documentation index, see [llms.txt](https://max-frontend.gitbook.io/react-router-course-ru/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://max-frontend.gitbook.io/react-router-course-ru/podklyuchaem_redux/storedispatch_redirekt.md).

# store.dispatch редирект

*ОБНОВЛЕНИЕ 2018: в учебнике хорошая теория, но ему уже два года. Проверяйте версии пакетов. За выходом нового учебника можно следить в* [*telegram канале*](http://bit.ly/2FI9nhs) *или* [*twitter*](http://bit.ly/2FU6zRL)

*На* [*канале*](http://bit.ly/2FI9nhs) *так же проводятся бесплатные вебинары, публикуются переводы и авторские материалы,* [*присоединяйтесь*](http://bit.ly/2FI9nhs)*!*

## store.dispatch редирект

Данная глава неспроста называется store.dispatch редирект. Пожалуй, факт, что мы должны выполнить редирект с помощью **store.dispatch** - является основополагающим в этом подходе.

Чего мы добьемся в таком случае?

Мы не нарушим однонаправленный (и самое важное, *четко контролируемый нами*) поток данных в приложении. По сути, весь роутинг - это действия (*actions*).

Большинство библиотек ([redux-router](https://github.com/acdlite/redux-router), [react-router-redux](https://github.com/reactjs/react-router-redux)) так и поступают. В них, каждое действие можно увидеть в логах.

Почему здесь, я не хочу разбирать эти отличные библиотеки? Потому что, я хочу показать вам как сделать редирект "вручную", чтобы вы четко понимали как это работает. Да, мы потеряем связь с [*redux-devtools*](https://github.com/gaearon/redux-devtools) (в данном курсе не используется), да мы не будем "синхронизировать" данные роутера в *store*... Но так ли это важно и необходимо?

Давайте просто будем использовать react-router напрямую. А в лог писать, только те действия с роутингом, которые нам действительно необходимы.

Напоминаю, что предыдущий исходный код, дал следующий результат: если мы пытаемся залогиниться - логируется LOGIN\_REQUEST и ничего не происходит.

![login\_req\_screen](/files/-LvLn_Y-M5Qjf55i8vVC)

Для начала, оформим все необходимое для имитации логина. В "заглушке" будем, помимо свойства name, добавлять свойство *isAuthenticated*

*src/actions/UserActions.js*

```javascript
...
export function login(payload) {
  return (dispatch) => {

    dispatch({
      type: LOGIN_REQUEST
    })

    setTimeout(() => {
      dispatch({
        type: LOGIN_SUCCESS,
        payload: {
          name: payload.name,
          isAuthenticated: true
        }
      })
    },2000)
  }
}
...
```

В редьюсере, соответственно, будем корректно обрабатывать измененный *action*:

*src/reducers*

```javascript
...
case LOGIN_SUCCESS:
      return {...state, name: action.payload.name, isAuthenticated: action.payload.isAuthenticated}
...
```

*На всякий случай: ... в начале и в конце = "другой код выше / ниже", а ... в строке return -* [*spread operator*](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Spread_operator)

Проверим:

![login\_success\_screen](/files/-LvLn_Y16wIan42VxEp8)

*LocalStorage* в данный момент никак не используем.

Немного порассуждаем: если бы у нас была возможность "диспатчить" редирект, где бы мы это сделали? Очевидно, что после LOGIN\_SUCCESS в таймауте.

Проблема в том, что мы не можем вызывать редирект, с помощью store.dispatch

**Вопрос**: как это исправить?

**Ответ**: написать middleware.

**Задача**: требуется написать middleware, который в случае: action.type = РОУТИНГ, выполнял бы переход (с помощью browserHistory, разумеется).

Дополнение **#1**: Было бы здорово, если бы мы имели возможность указывать push или replaceState метод.

**Решение** (*псевдо-код*):

```
import browserHistory
import КОНСТАНТА_РОУТИНГА

export const redirect = store => next => action => {
  if (action.type === КОНСТАНТА_РОУТИНГА) {
    browserHistory[МЕТОД](куда_перенаправить)
  }

  return next(action)
}
```

Предлагаю решить самостоятельно, а после сверится с кодом ниже.

### Решение: создание middleware для роутинга

*src/constants/Routing.js*

```javascript
export const ROUTING = 'ROUTING'
```

*src/middlewares/redirect.js*

```javascript
import { browserHistory } from 'react-router'

import {
  ROUTING
} from '../constants/Routing'

export const redirect = store => next => action => { //eslint-disable-line no-unused-vars
  if (action.type === ROUTING) {
    browserHistory[action.payload.method](action.payload.nextUrl)
  }

  return next(action)
}
```

События связанные с роутингом мы не будем обрабатывать редьюсером.

Обновим *actionCreator* (функцию-создатель действия):

*src/actions/UserActions.js*

```javascript
...
import {
  ROUTING
} from '../constants/Routing'

export function login(payload) {
  return (dispatch) => {

    dispatch({
      type: LOGIN_REQUEST
    })

    setTimeout(() => {
      dispatch({
        type: LOGIN_SUCCESS,
        payload: {
          name: payload.name,
          isAuthenticated: true
        }
      })

      dispatch({
        type: ROUTING,
        payload: {
          method: 'push', //или, например, replace
          nextUrl: '/admin'
        }
      })
    },2000)
  }
}
...
```

**Вопрос**: где мы должны добавить middleware в цепочку других middleware'ов ?

**Ответ**: там, где настраивается объект *store*

*src/store/configureStore.js*

```javascript
...
import { redirect } from '../middlewares/redirect'

export default function configureStore() {
  const store = compose(
    applyMiddleware(thunkMiddleware),
    applyMiddleware(createLogger()),
    applyMiddleware(redirect) // добавили редирект middleware
  )(createStore)(rootReducer)
...
```

Очистим метод *onEnter* у компонента `<Admin />`:

*src/components/Admin/index.js*

```javascript
import React, { Component } from 'react'

export default class Admin extends Component {
  static onEnter() {
    // nothing
  }
  render() {
    return (
      <div className='row'>
        <div className='col-md-12'>Раздел /admin</div>
      </div>
    )
  }
}
```

Откройте в браузере `http://localhost:3000/login` и попробуйте залогиниться (введите любое имя):

![login\_with\_redirect\_screen](/files/-LvLn_Y4i-T1cc4ZiG8-)

Теперь нажмите "назад" - вы должны оказаться на странице `/login`, так как мы использовали метод **push**. Данный метод добавляет страницу в историю браузера. **replace** же, не добавляет страницу в историю браузера, но тем не менее url меняет. Скоро мы поработаем с ним.

Не забывайте про возможность пользователя нажимать "назад/вперед".

**Итог**: мы научились делать редирект посредством **store.dispatch**, но сломали *onEnter hook*, теперь страница `/admin` доступна всегда. Исправим это в следующем уроке.

[Исходный код](https://github.com/maxfarseer/react-router-ru-tutorial/tree/middleware_redirect_v2) на данный момент.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://max-frontend.gitbook.io/react-router-course-ru/podklyuchaem_redux/storedispatch_redirekt.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
