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 для любых видов разработки



Хлопайте, если вам это нравится.