Недавно я познакомился с API React Hooks. Это кажется довольно интересным и может полностью изменить то, как мы делаем приложения React.
Вступление:
ПРИМЕЧАНИЕ. Это альфа-версия, поэтому, пожалуйста, пока не используйте ее в крупномасштабных производственных приложениях. Но я не думаю, что так долго будет.
Вы можете найти документацию здесь. Вкратце, API призван помочь следующим образом:
- Сокращение использования классов, поскольку они, кажется, сбивают с толку программистов, которые широко использовали их на других языках.
- Разделение проблем в коде компонента на основе логики, а не методов жизненного цикла - больше никакого дублирования кода в
componentDidMount
иcomponentDidUpdate
- Изолированное использование логики с отслеживанием состояния между компонентами без необходимости использования компонентов более высокого порядка или рендеринга.
Реализация:
Нам нужно придумать лучший пример приложения для проверки новых стеков, поскольку список дел становится очень простым и не всегда охватывает все элементы, которые мы хотим опробовать. Однако в этом случае я больше всего хотел проверить хук useReducer()
. Было бы неплохо иметь возможность повторно использовать большую часть кода редуктора, который у нас уже есть в наших приложениях. Итак, список задач у меня работает.
Базовая настройка:
Можно использовать обычный create-react-app
и довольно быстро начать работу, но я подозревал, что могут быть некоторые несоответствия версий библиотеки. Итак, я пошел с нуля с нуля. Действительно, возникла проблема с работой HMR (требуется как минимум v4.6.0):
- Установите менеджер пакетов, например
yarn
(илиnpm
), если он еще не установлен - Инициализируйте приложение с
yarn init
(иgit init
) - Сделайте папки
public
иsrc
в каталоге приложения - Добавьте
.gitignore
с обычными элементами, такими какnode_modules
иdist
- Добавьте базовый
index.html
в папкуpublic
:
- Установить babel:
yarn add --dev @babel/[email protected] @babel/[email protected] @babel/[email protected] @babel/[email protected]
- Добавьте
.babelrc
со следующим:
{ "presets": ["@babel/env", "@babel/preset-react"] }
- Установите
webpack
зависимости:yarn add --dev [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
- Добавьте
webpack.config.js
в каталог приложения:
- Добавьте зависимости React:
yarn add [email protected] [email protected] [email protected]
- Добавьте
index.js
в папкуsrc
:
- Добавьте
App.js
в папкуsrc
(оставьте пока комментарий к части списка дел. Мы раскомментируем их, как только сделаем их. Всегда лучше сначала запустить приложение):
- Добавьте
scripts
кpackage.json
:
"scripts": { "start": "webpack-dev-server --mode development", "build": "webpack --mode production" }
- Запустите приложение с
yarn run start
и убедитесь, что приложение с HMR работает должным образом наlocalhost:3000
.
Список дел:
Предпосылка заключалась в том, что мы хотим использовать код редуктора, поскольку он уже может существовать в приложении React. Итак, давайте сначала добавим редуктор, а затем поработаем над его использованием в приложении.
Можно иметь еще более простую логику для редуктора списка дел, используя везде только индексы, но по личному опыту я обнаружил, что использование идентификаторов безопаснее.
Переходя к хукам, в этом примере мы будем использовать useReducer
и useState
. Вы можете найти их документацию здесь и здесь.
useReducer
определяется следующим образом:
const [state, dispatch] = useReducer(reducer, initialState);
Это может показаться очень знакомым людям, которые какое-то время использовали редукторы в приложениях React. state
- нормальное состояние компонента; dispatch
используется для вызова обновления state
; reducer
определяет логику обновления; initialState
объявляет значение для инициализации state
.
В нашем примере родительский компонент, содержащий логику списка дел, объявляет state
с использованием useReducer
и передает функции CRUD, которые будут использовать dispatch
, дочерним компонентам.
2. useState
определяется следующим образом:
const [state, setState] = useState(initialState);
Здесь state
может быть любой переменной, которую в противном случае вы могли бы объявить с помощью this.state
в конструкторе. initialState
- начальное значение для этой переменной. setState
работает аналогично this.setState
, но зависит от объявленной здесь переменной. В сочетании с ловушкой useEffect
(в основном для обработки операций монтирования и обновления; не используется в этом примере), в идеале после этого объявления, это сгруппировало бы всю логику, связанную с переменной state
, в одном месте в коде компонента. Если его нужно использовать в нескольких компонентах, эту логику также можно обернуть в настраиваемый крючок.
В нашем примере операции CRUD над задачами обрабатываются реквизитами, которые передаются дочерним элементам от родительского компонента. Но локальную обработку обновления текста задачи может выполнять useState
.
В обработке обновлений text
и mode
было очень мало логики. В случае реальных приложений к ним будет привязана дополнительная логика, например, наличие различных разрешений на доступные режимы и требование проверки аутентификации перед редактированием. В таких случаях было бы разумно переместить логику редактирования mode
и text
в настраиваемые хуки и использовать их во всех компонентах.
Стиль и бег:
В качестве последнего штриха давайте добавим здесь немного стиля нашим компонентам.
И мы закончили. Вот как выглядит приложение:
Код этого примера доступен по адресу: https://github.com/nsuthar0914/react-hooks-webpack-hmr
Наблюдения:
- Такой подход может привести к гораздо более читаемому и сухому коду.
- Его можно использовать параллельно с существующим кодом без обязательного обновления всего его.
- Его довольно легко зацепить
С нетерпением жду возможности попробовать еще и посмотреть, как это работает с клиентами GraphQL.
- Нирадж Сутхар