# Хук состояния useReducer в React

Хук `useReducer` работает со стейтами. Это своего рода альтернатива `useState`. Хук `useReducer` позволяет нам добавлять в компонент функцию, называемую редьюсер.

Редьюсер - это такой тип простых, чистых функций, которые принимают объект предыдущего стейта и объект действия и возвращают объект нового стейта.

В хуке `useReducer` эта функция работает подобно `reducer` в Redux, она возвращает тот или иной результат в зависимости от определенного типа действия.

Давайте перейдем к реализации. Для примера сделаем счетчик с двумя кнопками. По клику на одну значение счетчика будет увеличиваться, на другую уменьшаться.

Для начала импортируем функцию нашего хука `useReducer`:

`import { useReducer } from 'react';`

Давайте теперь в функции компонента `App` обозначим стейт `count` и функцию `dispatch`, которая будет обновлять стейт:

`function App() { const [count, dispatch]; }`

В хук `useReducer` нам нужно передать функцию `reducer`, которую мы напишем позже и начальное значение стейта `count`, пусть оно будет `10`:

`function App() { const [count, dispatch] = useReducer(reducer, 10); }`

Давайте будем выводить `count` в абзац:

`return ( <p>count: {count}</p> );`

Теперь под абзацем добавим две кнопки. По клику на первую мы будем вызывать `reducer`, передавая ему тип действия `increase`, другими словами, по которому значение счетчика будет увеличиваться. По клику на вторую мы будем уменьшать значение счетчика, передавая в `reducer` тип действия `decrease`:

`return ( <> <p>count: {count}</p> <button onClick={() => dispatch({ type: 'increase' })}>+</button> <button onClick={() => dispatch({ type: 'decrease' })}>-</button> </> );`

И наконец, нам остается написать наш `reducer`, который будет вычислять и возвращать следующее значение стейта, в зависимости от действия, которое мы передали в функцию `dispatch`.

Давайте разместим функцию `reducer` сразу после строки импорта, но перед функцией компонента `App`. Функция `reducer` принимает параметрами наш стейт и объект `action`, у которого нас интересует свойство `type`:

`function reducer(count, action) { switch (action.type) { } }`

Оформим этот кусочек кода, придерживаясь соглашения в React, в виде конструкции `switch-case`. Если значение `type` было в `increase`, то значение стейта увеличится на `1`, если `decrease`, то уменьшится на `1`. По умолчанию `reducer` вернет неизмененный стейт.

`function reducer(count, action) { switch (action.type) { case 'increase': return count + 1; case 'decrease': return count - 1; default: return count; } }`

Соберем все вместе и получим следующий код:

`import { useReducer } from 'react'; function reducer(count, action) { switch (action.type) { case 'increase': return count + 1; case 'decrease': return count - 1; default: return count; } } function App() { const [count, dispatch] = useReducer(reducer, 10); return ( <> <p>count: {count}</p> <button onClick={() => dispatch({ type: 'increase' })}>+</button> <button onClick={() => dispatch({ type: 'decrease' })}>-</button> </> ); } export default App;`

Нужно отметить, что этот хук идеален для компонентов со сложной логикой обновления стейтов.

Пусть у вас на экране отображается какое-то слово (например `'React'`). Заведите для этого соответствующий стейт с начальным значением. Пусть у вас будет две кнопки. По нажатию на первую в конец вашего слова каждый раз будет дописываться восклицательный знак, а на вторую - вопросительный. Для решения задачи используйте хук `useReducer`.

↑