В React управление состоянием компонентов всегда было проблемой. Традиционно использовались компонент класса и подход жизненного цикла, но этот подход приводит к избыточному коду, который трудно поддерживать. Появление React Hooks решает эту проблему, позволяя нам реализовать управление состоянием аналогично компонентам классов в функциональных компонентах. В этой статье я покажу вам, как использовать React Hooks для реализации управления состоянием сложных компонентов.
Основы управления состоянием — useState Hook
UseState — один из наиболее часто используемых хуков, которые позволяют нам определять состояние в функциональном компоненте и обновлять его в компоненте. Вот простой пример:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount(count + 1);
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
В приведенном выше коде мы определяем состояние счетчика с помощью useState и обновляем его с помощью метода setCount. Каждый раз, когда нажимается кнопка Increment, значение count увеличивается на 1.
Расширенный уровень управления состоянием — useReducer Hook
Когда состояние компонента сложное, использование useState может привести к путанице в коде. На этом этапе рассмотрите возможность использования useReducer. UseReducer — это еще один способ управления состоянием, который позволяет нам лучше организовать наш код и поместить логику для обновления состояния внутри функции редуктора.
import { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
}
В приведенном выше коде мы определяем счетчик состояний с помощью useReducer и помещаем логику обновления состояния в функцию редуктора. Каждый раз, когда нажимается кнопка «Увеличить» или «Уменьшить», запускается соответствующее действие.
Практика — реализация TodoList с использованием React Hooks
После введения useState и useReducer выше, давайте реализуем компонент TodoList. Этот компонент имеет следующие функции:
- Отображает все элементы списка задач
- Добавить новый элемент списка дел
- Удалить выполненный элемент задачи
Во-первых, нам нужно определить компонент TodoItem, который отображает задачу для каждого элемента.
function TodoItem({ text, completed, onClick }) {
return (
<li style={{ textDecoration: completed ? 'line-through' : 'none' }} onClick={onClick}>
{text}
</li>
);
}
Далее мы можем начать писать компонент TodoList. Поскольку нам нужно управлять состоянием нескольких элементов todo, более уместно использовать useReducer.
import { useReducer } from 'react';
import TodoItem from './TodoItem';
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';
const DELETE_TODO = 'DELETE_TODO';
function reducer(state, action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
id: state.length + 1,
text: action.text,
completed: false,
},
];
case TOGGLE_TODO:
return state.map(todo =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
);
case DELETE_TODO:
return state.filter(todo => todo.id !== action.id);
default:
throw new Error();
}
}
export default function TodoList() {
const [state, dispatch] = useReducer(reducer, []);
function handleAdd(text) {
dispatch({ type: ADD_TODO, text });
}
function handleToggle(id) {
dispatch({ type: TOGGLE_TODO, id });
}
function handleDelete(id) {
dispatch({ type: DELETE_TODO, id });
}
return (
<div>
<ul>
{state.map(todo => (
<TodoItem
key={todo.id}
text={todo.text}
completed={todo.completed}
onClick={() => handleToggle(todo.id)}
/>
))}
</ul>
<input type="text" placeholder="Add a new todo" onKeyDown={e => e.key === 'Enter' && handleAdd(e.target.value)} />
<button onClick={() => handleDelete()}>Delete Completed Todos</button>
</div>
);
}
В приведенном выше коде мы определяем три типа действий, соответствующих разным операциям, и обрабатываем соответствующую логику в функции редуктора. В компоненте TodoList мы определяем состояние задач с помощью useReducer и предоставляем три метода handleAdd, handleToggle и handleDelete для добавления, переключения и удаления элементов задач. В то же время мы также отображаем элемент ввода и элемент кнопки для добавления новых элементов списка задач и удаления завершенных элементов списка задач соответственно.
На данный момент мы реализовали простой компонент TodoList. Использование useReduce позволяет нам лучше организовать наш код и сделать его более понятным.
Краткое содержание
React Hooks обеспечивают более лаконичный способ управления состоянием компонентов. Использование useState и useReduce позволяет нам лучше организовать наш код и улучшить его читабельность и удобство сопровождения.
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .
Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.