# Подключаем redux

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

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

## Подключаем redux

*Если вы не знакомы с redux, вам поможет* [*этот туториал*](https://www.gitbook.com/book/maxfarseer/redux-course-ru/details)

```
npm i --save redux react-redux
npm i --save-dev redux-logger redux-thunk
```

(вы всегда можете проверить версии в *package.json*, если что-то вдруг перестало работать. "Мир реакт" активно развивается)

Нам необходимо подговиться для решения следующей задачи:

Пользователь кликает на "Админка".

* Если пользователь залогинен - пропускаем его на страницу
* Если пользователь не залогинен - отправлям его на страницу логина

При чем здесь *redux*? Разве такую задачу мы уже не решили с помощью хука на *onEnter?*

Это отличный вопрос! Делайте так, как необходимо для приложения, а не просто тащите в проект все модные технологии. Тем не менее, у нашей задачи есть свои цели:

* во время логина мы сделаем задержку (как будто ждем ответ от сервера), и лишь когда пришел ответ - перенаправим браузер пользователя на /admin
* роутинг будет выполняться посредством **store.dispatch**

**В итоге**, решив данную задачу, у вас будет четкое понимание как сделать любой подобный запрос с редиректом, ведь по факту все сводится к одному и тому же: когда получен ответ - сделай редирект.

(*код ниже выполнять не обязательно, так как можно взять исходный код в конце раздела.*)

Для начала работы с нашим приложением, необходимо внести множество изменений. Для тех, кто знаком с **redux** - ничего нового. Тезисно и частично с кодом привожу здесь, так как, возможно вы читаете в формате книги вдали от ПК и хотите повторить какие-то моменты связанные с подключением redux в проект:

* Обернем `<Router />` в `<Provider />`

*src/index.js*

```javascript
...
import { Provider } from 'react-redux'
import configureStore from './store/configureStore'
...

const store = configureStore()

render(
  <Provider store={store}>
    <Router history={browserHistory} routes={routes} />
  </Provider>,
  document.getElementById('root')
)
```

* создаем *константы* для пользователя

*src/constants/User.js*

```javascript
export const LOGIN_REQUEST = 'LOGIN_REQUEST'
export const LOGIN_FAIL = 'LOGIN_FAIL'
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'
export const LOGOUT_SUCCES = 'LOGOUT_SUCCESS'
```

* создаем *actions* для пользователя

*src/actions/UserActions.js*

```javascript
/* eslint-disable no-unused-vars */

import {
  LOGIN_REQUEST,
  LOGIN_FAIL,
  LOGIN_SUCCESS,
  LOGOUT_SUCCESS
} from '../constants/User'

export function login(payload) {
  // TODO
  return {
    type: LOGIN_REQUEST
  }
}

export function logout() {
  return {
    type: LOGOUT_SUCCESS
  }
}

/* eslint-enable no-unused-vars */
```

* создаем *reducer* для пользователя

*src/reducers/user.js*

```javascript
import {
  LOGIN_REQUEST,
  LOGIN_FAIL,
  LOGIN_SUCCESS,
  LOGOUT_SUCCESS
} from '../constants/User'

const initialState = JSON.parse(window.localStorage.getItem('rr_user')) || {}

export default function userstate(state = initialState, action) {

  switch (action.type) {

    case LOGIN_REQUEST:
      // TODO
      return {}

    case LOGIN_SUCCESS:
      // TODO
      return {}

    case LOGIN_FAIL:
      // TODO
      return {}

    case LOGOUT_SUCCESS:
      // TODO
      return {}

    default:
      return state
    }
}
```

* Сразу создадим файл с главным редьюсером, где в будущем сможем "скомбинировать" больше редьюсеров (на данный момент у нас только один)

*src/reducers/index.js*

```javascript
import { combineReducers } from 'redux'
import user from './user'
import popup from './popup'

export const rootReducer = combineReducers({
  user,
  popup
})
```

* конфигурируем *store*
* добавляем несколько *middleware* ([logger](https://github.com/fcomb/redux-logger) - для логов и [thunk](https://github.com/gaearon/redux-thunk) - для асинхронных запросов)

*src/sotre/configureStore*

```javascript
import { createStore, applyMiddleware, compose } from 'redux'
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
import { rootReducer } from '../reducers'

export default function configureStore() {
  const store = compose(
    applyMiddleware(thunkMiddleware),
    applyMiddleware(createLogger())
  )(createStore)(rootReducer)

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextRootReducer = require('../reducers').rootReducer
      store.replaceReducer(nextRootReducer)
    });
  }

  return store
}
```

* превратим "тупой компонет" `<Login />` в "умный компонент" `<LoginPage />` (то есть подключим его (*connect*))

*src/containers/LoginPage/index.js*

```javascript
import React, { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as UserActions from '../../actions/UserActions'

export class LoginPage extends Component {
  handleSubmit(e) {
    e.preventDefault()
    this.props.actions.login({name: e.target.elements[0].value})
  }
  render() {
    return (
      <div className='row'>
        <div className='col-md-12'>
          <form className='form-inline' onSubmit={::this.handleSubmit}>
            <input className='form-control' type='text' placeholder='login'/>{' '}
            <button className='btn btn-primary' type='submit'>Войти</button>
          </form>
        </div>
      </div>
    )
  }
}

function mapStateToProps() {
  return {}
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(UserActions, dispatch)
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(LoginPage)
```

Обратите внимание, что мы стали передавать объект user

```javascript
{
    name: логин
}
```

До этого момента, мы передавали строку с именем. Так же немного изменилось оформление компонента.

В *routes.js* изменили подключение `<Login />` на `<LoginPage />`

В будущем вы сможете добавить юзерам роль в проекте и так далее.

На всякий случай, напоминаю, что:

```javascript
::this.handleSubmit
```

Эквивалентно

```javascript
this.handleSubmit.bind(this)
```

**Итого**: мы подключили redux, создав необходимый каркас для дальнейшей деятельности.

[Исходный код](https://github.com/maxfarseer/react-router-ru-tutorial/tree/add_redux_v3_prepare) на текущий момент. Не забудьте скачать новые зависимости:

```
npm install
```

и очистить *localStorage*

```
localStorage.clear() //выполняется из консоли хрома, например
```


---

# Agent Instructions: 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.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.
