Итак, переходим ко второй части! В первой части мы рассмотрели, как использовать React Context API для передачи значений в нашем приложении.
Во второй части мы рассмотрим, как использовать хук useReducer для поддержания состояния во всем приложении. А также использование React Context API для передачи этого состояния всему приложению.
Мы начнем с добавления useReducer в наш компонент ProductsProvider.
//products_context.js
import React, {useReducer} from "react";
import reducer from "../products_reducer";
export const ProductsProvider = ({ children }) => {
const initialState = {
productsLoading: false,
products: [],
};
const [state, dispatch] = useReducer(reducer, initialState);
return (
<ProductContext.Provider value={}>
{children}
</ProductContext.Provider>
);
};
Чтобы объяснить части useReducer, у нас есть state – текущее состояние, dispatch – тип и полезная нагрузка, где тип указывает редуктору, какие действия нужно предпринять, а полезная нагрузка – данные, которые нужно передать редуктору, reducer – созданная нами функция, которая решает, как изменить состояние на основе нашего типа диспетчера, и, наконец, initialState, который не требует пояснений.
Итак, давайте определим нашу функцию reducer.
//products_reducer.js
const products_reducer = (state, action) => {
if (action.type === "GET_PRODUCTS_BEGIN") {
return { ...state, productsLoading: true };
}
if (action.type === "GET_PRODUCTS_SUCCESS") {
return {
...state,
productsLoading: false,
products: action.payload,
};
}
};
export default products_reducer;
Наша функция reducer принимает 2 аргумента, currentState и действие, по сути, ваше действие – это отправка. Редуктор проверяет тип действия и возвращает обновленное состояние, основанное на типе действия.
Как же использовать dispatch для обеспечения правильного типа, чтобы reducer мог обновить состояние? Давайте вернемся к products_context.js, в нашу функцию ProductsProvider, где мы определили наш useReducer.
//products_context.js
export const ProductsProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
const fetchProducts = async () => {
dispatch({ type: GET_PRODUCTS_BEGIN });
let response = {};
try {
response = await axios.get(url);
let products = response.data;
dispatch({ type: GET_PRODUCTS_SUCCESS, payload: products })
} catch (error) {
console.log({ error });
}
};
return (
<ProductContext.Provider value={{ ...state , fetchProducts }}>
{children}
</ProductContext.Provider>
);
};
В нашей функции fetchProducts мы используем функцию dispatch для изменения состояния, обратите внимание, что во второй функции dispatch мы передаем ответ от нашего вызова API в качестве полезной нагрузки. Это, в свою очередь, будет использовать значение полезной нагрузки в функции reducer с типом “GET_PRODUCTS_SUCCESS”.
Наконец, мы передаем наше состояние в значение prop ProductContext.Provider, поэтому при каждом обновлении состояния компоненты, использующие это значение состояния, будут перерендерированы.
//products_context.js
<ProductContext.Provider value={{ ...state , fetchProducts }}>
{children}
</ProductContext.Provider>
Здесь, на странице отображения продукта, мы можем деструктурировать наши значения состояния и использовать их соответствующим образом для отображения данных.
//Product.js Page
import { useProductContext } from "../products_context";
const { products , productsLoading , fetchProducts } = useProductContext();
На этом мы завершаем серию статей о React Context API и useReducer. Надеюсь, вы узнали что-то новое из этой статьи. Поделитесь в комментариях ниже, как вы работаете с состояниями в своем приложении.