25 октября 2015 г. — Обновлено 21 ноября 2017 г.

Этот пост был процитирован с Github.
Этот учебник был написан, чтобы сделать простое введение в Redux. Проект был разработан с использованием ES6 и ReactJS, обязательными условиями являются ES6 и ReactJS.
Установка
Клонируйте репозиторий и установите зависимости.
git clone https://github.com/yildizberkay/redux-example.git cd redux-examplenpm install npm start open http://localhost:3000
ESLint
npm run lint
Зачем нам нужен Redux?
Давайте подумаем об обычном приложении React. Есть компоненты, состояния, реквизиты и действия API. Компонент вызывает другие компоненты, и если вы запускаете состояние пользовательского интерфейса, обновляется представление и т. д. Наконец, приложение становится сложным, и вы не можете им управлять.
React – это библиотека JavaScript для создания пользовательских интерфейсов в Facebook и Instagram. Многие считают React буквой V в MVC.
Источник: https://facebook.github.io/react/docs/why-react.html
Нам нужен контейнер состояния, такой как Redux. Как Redux решает эту проблему? По сути, существует единственный источник хранилища, который доступен только для чтения. Если вы хотите выполнить такое действие, как загрузка фотографий из API, вы должны сделать это с помощью действий и редюсеров.
В Redux есть 3 основные части: действия, редукторы и хранилище.
Действия
Действия используются для получения данных. В этой части можно делать запросы к API.
Действия — это полезные данные, которые отправляют данные из вашего приложения в ваш магазин. Это единственный источник информации для магазина.
В следующем примере есть действие с именем searchPhotoAction. Это действие возвращает функцию, содержащую searchWithPhotoAPI и функцию dispatch, уведомляющую store. Как видите, в первую очередь dispatch отправляет тип «SEARCH_PENDING», это показывает счетчик на экране. После этого, если запрос выполнен успешно, dispatch отправляет «SEARCH_DONE», массив фотографий и другую информацию.
function searchWithPhotoAPI(keyword, page, dispatch) {
if (page >= 2) {
dispatch({
type: types.SEARCH_PENDING_FOR_NEXT,
});
} else {
dispatch({
type: types.SEARCH_PENDING,
});
}
photoSearch(keyword, page, (data) => {
dispatch({
type: types.SEARCH_DONE,
photos: data.photos,
page,
keyword,
});
});
}
export function searchPhotoAction(keyword, page = 1) {
return (dispatch) => {
searchWithPhotoAPI(keyword, page, dispatch);
};
}
Редукторы
Данные поступают в редьюсеры, и здесь они преобразуются. После этого он передается на просмотры. На этом шаге вы можете комбинировать предыдущее состояние со следующим.
В следующем коде возвращаемое состояние изменяется в соответствии с action.type. Если action.type равно types.SEARCH_PENDING, мы отобразим счетчик.
const searchPhotos = (state = initialState, action) => {
switch (action.type) {
case types.SEARCH_DONE:
return {
...state,
photos: [...state.photos, ...action.photos],
status: 'DONE',
page: action.page,
keyword: action.keyword,
};
case types.SEARCH_PENDING_FOR_NEXT:
return {
...state,
status: 'PENDING_FOR_NEXT',
};
case types.SEARCH_PENDING:
return {
...state,
photos: [],
status: 'PENDING',
};
default:
return state;
}
}
Магазин
В Redux есть только один магазин. Его можно создать напрямую с помощью createStore, а также с помощью applyMiddleware.
// containers/App.jsx
const reducer = combineReducers({ searchPhotos });
const store = createStore(reducer, {}, applyMiddleware(thunk));
const App = () => (
<div>
<Provider store={store}>
<SearchApp />
</Provider>
</div>
)
Вызов действий
Прежде чем вызывать действие, мы должны объединить действия и функцию отправки. Функция connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]) подключает компонент React к хранилищу Redux.
bindActionCreators(actionCreators, dispatch) объединяет действия и функцию отправки.
// containers/SearchApp.jsx
...
class SearchApp extends PureComponent {
render() {
const actions = bindActionCreators(action, this.props.dispatch);
return (
<div>
<div id="header" className="header">
<div className="container">
<div className="row">
<div className="col-md-6 col-md-offset-3 search-bar-content">
<h1>Search on 500px</h1>
<SearchInput actions={actions} status={this.props.status} />
</div>
</div>
</div>
</div>
<div className="container">
<PhotoList actions={actions} photos={this.props.photos} status={this.props.status} />
</div>
</div>
);
}
}
...
export default connect(
mapStateToProps,
)(SearchApp);
Теперь вы можете вызывать действия с помощью следующего кода.
actions.searchPhotoAction(keyword, page)
Структура каталогов
Root
├── public
│ ├── actions
├── src
│ ├── actions
│ │ └──
│ ├── api
│ │ └──
│ ├── components
│ │ └──
│ ├── constants
│ │ └──
│ ├── containers
│ │ └──
│ ├── reducers
│ │ └──
│ ├── stylesheets
│ │ └──
│ └── index.js
├── .eslintignore
├── .eslintrc.json
├── package.json
└── README.md
Ресурсы
- https://facebook.github.io/реагировать/
- http://rackt.github.io/redux/
- https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb
Список изменений
21 ноября 2017 г.
- README обновление.
- Обновление версии ReactJS. [15.6.2]
- Обновление редукс-версии. [3.7.2]
- Миграция React-скриптов.
25 октября 2015 г.
- Получить поддержку для всех браузеров. @pcanterini PR
- Добавлены правила Airbnb ESLint.
12 октября 2015 г.
- Начальная фиксация.
Первоначально опубликовано на yildizberkay.com 25 октября 2015 г.