React context API значительно упростил управление состоянием по сравнению с Redux. Но все же многие разработчики используют Redux, так как это тоже хороший выбор.
Очень легко управлять состоянием вашего реагирующего приложения с помощью контекстного API. Но в некоторых случаях (когда нужно управлять огромными данными и манипулировать ими) это становится беспорядочным. Возьмите это в качестве примера-
В этом примере мне нужно создать множество методов для манипулирования и обмена данными с его дочерними компонентами. Но хуки useReducer могут позаботиться об этой части.
В этой статье я покажу, как можно использовать хуки useReduce с контекстным API для лучшего управления состоянием.
Сначала давайте познакомимся с хуком useReducer. См. схему использованияReducer
Обычно хук useReducer принимает два аргумента: редуктор и начальное состояние, возвращает состояние и метод отправки (действия).
Начнем с пустого проекта create-react-app и удалим лишнее. Создайте три новые папки в srcFloder, components, context и reducer.
Теперь давайте создадим контекст для приложения.
import React, {useReducer, createContext } from 'react' const TodoContext = createContext() export function TodoProvider({reducer, state, children}) { return ( // value will contains state and dispatch as useReducer return state and dispatch <TodoContext.Provider value={useReducer(reducer, state)}> {{...children}} </TodoContext.Provider> )} export default TodoContext
Мы использовали хук useReducer в значении провайдера контекста. Итак, провайдер контекста имеет два объекта — состояние и отправку. Когда мы будем использовать контекст с помощью useContext, он вернет массив [состояние, отправка].
Теперь давайте обернем наше приложение с помощью TodoProvider, чтобы мы могли получать [состояние, отправку] от дочерних компонентов.
import React from 'react' import './App.css'; import TodoList from './components/TodoList'; import {TodoProvider} from './context/TodoContext' // we haven't create reducer yet. We will create now import {initialState, reducer} from './reducer/TodoReducer' function App() { return ( <TodoProvider reducer={reducer} state={initialState}> <div className="App container"> <TodoList/> </div> </TodoProvider> ); } export default App;
Обратите внимание, что мы импортируем TodoReducer из папки редуктора и TodoList из папки компонентов. Но мы еще не создали это. Позже мы создадим TodoList. Сейчас мы создадим редюсер.
export const ACTION_TYPES = { ADD_TODO: 'add_todo', TOGGLE_COMPLETE: 'toggle_complete', REMOVE_TODO: 'remove_todo' } export const initialState = { list: [ {id:1,task: 'Do some rook', complete: false}, {id:2,task: 'Do some rool', complete: false}, {id:3,task: 'Write some react ', complete: false} ] } export function reducer(state, action){ switch(action.type){ case ACTION_TYPES.ADD_TODO: return addTodo(state, action.payload) case ACTION_TYPES.REMOVE_TODO: return removeTodo(state, action.payload) case ACTION_TYPES.TOGGLE_COMPLETE: return toggleTodo(state, action.payload) default: return state } } function addTodo(state, newTodo){ let list = state.list const newOne = {id:list.length+1,task: newTodo, complete: false} return {...state, list: [...list, newOne]} } function removeTodo(state, id){ let list = state.list let newList = list.filter((el)=> el.id !== id) return {...state, list: newList} } function toggleTodo(state, id){ let newList = state.list.map(obj=> obj.id===id? {...obj, complete: !obj.complete} : obj) return {...state, list: [...newList]} }
В этом редюсере есть три действия: добавить новую задачу , удалить задачу и переключить завершение. .
Теперь добавим компонент TodoList с формой и обработчиком. Он состоит из двух частей. Один список задач и двеформы с одним вводом. Для разработки этих компонентов мы будем использовать Materialize CSS. Включите CDN Materializecss в заголовок index.htmиз общедоступной папки. Компонент TodoList будет таким:
// include materialized css cdn to the header of index.html file import React, { useContext, useState } from 'react' import TodoContext from '../context/TodoContext' import { ACTION_TYPES } from '../reducer/TodoReducer' function TodoList() { const [state, dispatch] = useContext(TodoContext) const [task,setTask] = useState("") const handleSubmit = (e)=>{ e.preventDefault() dispatch({ type: ACTION_TYPES.ADD_TODO, payload: task }) setTask("") } return ( <div className="row"> <div className="col s6 offset-s3"> <ul className="collection"> {state.list.map(l => ( <li className="collection-item" key={l.id}> <label> <input type="checkbox" checked={l.complete?"checked":""} onChange={(e)=>{dispatch({ type: ACTION_TYPES.TOGGLE_COMPLETE, payload: l.id })}} className="filled-in"/> <span>{l.task}</span> </label> <button className="secondary-content btn" onClick={()=>{dispatch({ type: ACTION_TYPES.REMOVE_TODO, payload: l.id })}}>x</button> </li> ))} </ul> <form onSubmit={handleSubmit}> <div className="input-field"> <input id="email" type="text" className="validate" placeholder="task" onChange={(e)=>{setTask(e.target.value)}} value={task}/> </div> </form> </div> </div> ) } export default TodoList
Вывод будет таким, если вы добавили материализованный css cdn.
Вы можете найти полный код в этом репозитории github —
Вы также можете посетить мой профиль на Fiverr для любых видов разработки
Хлопайте, если вам это нравится.