Redux помогает нам централизовать и управлять данными нашего приложения глобально, без необходимости передавать состояние родительским компонентам и устраняет проблемы, связанные с бурением реквизитов. Не каждое приложение нуждается в использовании Redux, но по мере роста вашего приложения использование Redux неизбежно.
Теперь у нас есть redux-toolkit, который стал официальной рекомендацией для написания логики redux. Чтобы понять плюсы использования redux-toolkit, мы должны знать минусы использования традиционного кода Redux. Поскольку redux-toolkit – это просто уровень абстракции над традиционным кодом, мы должны знать основную архитектуру Redux, чтобы мы могли легко оценить проблемы, которые он решает.
Прежде чем использовать Redux Toolkit, давайте разберемся, как установить/использовать Redux в приложении react, а затем в следующем блоге мы обсудим, как Redux toolkit сокращает код и действует как абстракция.
1. Инициализируйте ваше приложение react:
Откройте терминал и введите следующую команду cmd для инициализации вашего проекта с предопределенным шаблоном
$ npx create-react-app react-redux-demo
затем перейдите в каталог проекта и выполните команду
npm start
2. Установите redux и react-redux:
React Redux позволяет вашим компонентам React общаться с хранилищем Redux и отправлять данные (модное слово – отправлять действия) в хранилище, чтобы оно обновлялось в соответствии с выполненным действием. Для этого введите следующую команду:
npm install redux react-redux
3. Создание магазина redux:
Мы создадим две папки:
redux (файлы, связанные с конфигурацией redux)
store (файлы, связанные с магазином redux).
Внутри папки redux мы создадим файл createStore.ts
.
Минимальный файл createStore.ts:
import rootReducer from "./reducers";
import { createStore } from "redux";
const store = createStore(rootReducer);
export { store };
Мы используем createStore из redux для создания магазина для нашего приложения и экспортируем магазин из этого файла.
Используемый в этом файле rootReducer будет рассмотрен позже.
4. Предоставляем этот магазин нашему приложению React:
Теперь, когда у нас есть готовый магазин, нам нужен способ доступа к нему для наших компонентов. Для этого мы будем использовать Provider из react-redux.
На корневом уровне нашего приложения мы создадим файл под названием AllProvider.tsx (этот файл действует как обертка для наших компонентов react).
import GlobalStyle from "styles";
import App from "./App";
import { Provider } from "react-redux";
import { store } from "redux/createStore";
const AllProvider = () => {
return (
<Provider store={store}>
<GlobalStyle />
<App />
</Provider>
);
};
export default AllProvider;
Теперь, когда мы обернули наше приложение провайдером, наше приложение может взаимодействовать/получать доступ к данным, хранящимся в хранилище redux. Теперь давайте попробуем придумать, как поместить некоторые данные в хранилище.
5. Размещение данных в нашем хранилище:
Чтобы создать/обновить/удалить данные в хранилище, нам нужно диспетчеризировать действия от компонентов React, а затем на основе диспетчеризированного действия мы будем выполнять некоторые операции.
Диспетчеризация действий
Давайте рассмотрим приложение для добавления постов (не очень полезное приложение, но оно выполняет свою работу).
Мы создадим три папки внутри нашей папки store:
папка types
В этой папке мы создадим файл postTypes.ts.
const ADD_POST = "ADD_POST";
export const PostTypes = {
ADD_POST,
};
Здесь мы определяем типы/случаи использования, которые могут быть выполнены. Мы создали здесь тип ADD_POST, чтобы этот тип мог быть использован создателем действия при отправке действия, а этот тип мог быть использован редуктором, чтобы принять это как случай. Мы будем использовать одну и ту же константу типа в редукторах и в файле actions, чтобы избежать опечаток.
папка actions
Мы создадим файл с названием postActions.ts:
import { PostTypes } from "store/types/postTypes";
export const addPost = (post: any) => ({
type: PostTypes.ADD_POST,
post,
});
Здесь мы создаем создателя действия addPost, который возвращает действие. (Действие – это просто объект, который имеет две вещи: тип и полезную нагрузку. Создатель действия – это просто функция, которая просто возвращает действие). Это функция, которая будет отправлять данные в наш магазин.
папка reducers
В этой папке хранятся традиционные операторы switch case, помогающие нам определить, как будет обновляться состояние в зависимости от типов:
import { PostTypes } from "store/types/postTypes";
const INITIAL_STATE: any[] = [];
const postReducer = (state = INITIAL_STATE, action: actionMapType) => {
switch (action.type) {
case PostTypes.ADD_POST: {
const updatedState = [...state];
updatedState.push(action.post);
return updatedState;
}
default:
return state;
}
};
export default postReducer;
Теперь, когда у нас есть готовый редуктор, давайте передадим этот редуктор в наш магазин. Помните, мы использовали rootReducer при создании нашего магазина, теперь вы знаете, откуда взялся этот rootReducer, но все же есть одна загвоздка. В реальном приложении у нас никогда не будет одного редуктора (если это так, пожалуйста, используйте состояние компонента). Поэтому для приложения, в котором есть несколько редукторов, мы объединим их (да, буквально, combineReducers) в один и передадим его в наш магазин, как показано ниже:
Внутри папки redux мы создадим файл reducer.ts.
import { combineReducers } from "redux";
import postReducer from "store/reducers/postReducer";
const rootReducer = combineReducers({
posts: postReducer,
});
export default rootReducer;
export type RootState = ReturnType<typeof rootReducer>;
Вуаля, наш магазин redux готов отдавать и получать данные, используя useSelector() (аналогично mapStateToProps в классе компонентов) и useDispatch() (аналогично mapDispatchToProps в классе компонентов) соответственно. Давайте посмотрим, как это сделать, и все будет в порядке:
import { useDispatch } from "react-redux";
import { CanvasWrapper } from "./styles";
import { addPost } from "store/actions/postActions";
import { RootState } from "redux/reducers";
const Canvas = () => {
const dispatch = useDispatch();
const posts = useSelector((state: RootState) => state.posts);
const addPostHandler = () => {
const newPost = {
title: "Hello this is a post",
};
dispatch(addPost(newPost));
};
return (
<CanvasWrapper>
<button onClick={addPostHandler}>Add post</button>
</CanvasWrapper>
);
};
export default Canvas;
Мы отправляем addPost() для отправки нового поста в магазин, затем действие попадает в редуктор, и выполняется случай, соответствующий типу действия. Мы получаем доступ к постам внутри хранилища с помощью useSelector(). Имя ключа будет таким же, как мы определили в функции combineReducers().
Вот так мы соединяем redux с нашими компонентами react с помощью react-redux. Приведенный выше код может оказаться слишком сложным для новичков и может показаться непосильным, поэтому в следующем блоге мы расскажем, как redux-toolkit решает многие вопросы и упрощает использование redux.
Спасибо и счастливого кодинга…