Как управлять сложным состоянием пользовательского интерфейса с помощью хука useReducer вместо редукса
Если вы тот, кто использует самую популярную библиотеку внешнего интерфейса Реагировать для создания своего пользовательского интерфейса вы наверняка слышали о свойствах и состоянии, которые запускают обновление пользовательского интерфейса при изменении любого из них; государство может быть местным
состояние (синхронное) или состояние сети (асинхронное).
Управление состоянием в React всегда было предметом разговоров с таким количеством библиотек, таких как: redux
, mobx
, recoil
и этот список можно продолжить, позвольте мне объяснить вам, как мы можем использовать это без добавления каких-либо дополнительных зависимостей к приложению и уменьшения размера пакета приложения.
Если вы уже давно пользуетесь React (по крайней мере, с React 16.3), возможно, вы слышали об одной из самых популярных библиотек Редукс для управления сложным состоянием пользовательского интерфейса из-за его предсказуемого состояния и поддержки асинхронного управления состоянием с помощью редукционный преобразователь а также редукс-сага библиотеки.
Существует множество библиотек, которые вы можете использовать в качестве промежуточного программного обеспечения в избыточности и расширить возможности избыточности. Если вы настраиваете редукс с нуля, вам необходимо настроить шаблонный код, прежде чем вы начнете над ним работать. Последние версии Redux предлагают API на основе хуков, чтобы уменьшить некоторые шаблоны, но все же вам нужно знать о действия, редукторы, промежуточное ПОи так далее.
Если вы используете последнюю версию React или React 16.8 или выше, возможно, вы уже используете одну из самых популярных функций, представленных в React: крючки. Хуки помогают вам писать компоненты без написания классов и с легкостью управлять состоянием реагирующего приложения.
В этом посте я объясню использование использованиередьюсер крючок с помощью других крючков, таких как использованиеЭффект, использовать памятку, useRefа также использование состояния для управления сложным состоянием пользовательского интерфейса без использования избыточности. Этот пост предполагает, что вы все знаете основы хуков и как их использовать. Если вы не использовали его раньше, я рекомендую вам всем прочитать официальную документацию для начала работы.
Предположим, что мы создаем простое приложение CRUD для библиотеки книг, в котором вы можете добавлять, удалять и управлять своей библиотекой в зависимости от ваших интересов. Я использую один из шаблонов пользовательского интерфейса React, широко используемых с избыточностью, шаблон контейнера и презентационных компонентов чтобы продемонстрировать этот пример, он может соответствовать любому шаблону, который вы уже используете.
books-container.js
import React, {useReducer, useMemo, useEffect, useRef} from 'react'
import _ from 'lodash'
import BooksLayout from './books-layout'
const bindActionCreators = (reducerMap, dispatch) =>
_.reduce(
reducerMap,
(result, val, type) => ({
...result,
[type]: payload => dispatch({type, payload}),
}),
{}
)
const initialState = {
books: {},
bookReadState: null
bookDeleteState: null
bookUpdateState: null
}
const reducerMap = {
setBooks: (state, books) => ({
...state,
books,
}),
updateBook: (state, book) => ({
...state,
books:
},
deleteBook: (state, book) => ({
...state,
books:
}),
setBookReadState: (state, bookReadState) => ({
...state, bookReadState
}),
setBookUpdateState: (state, bookUpdateState) => ({
...state, bookUpdateState
}),
setBookDeleteState: (state, bookDeleteState) => ({
...state, bookDeleteState
}),
}
const useService = ({id, actions}) => {
const abortController = useRef(new global.AbortController())
actions = useMemo(
() => ({
...actions,
readBooks: async () => {
try {
const data = await readBooks({
fetchCallback: actions.setBookReadState})
actions.setBooks(data)
} catch(error) {
}
},
updateBook: async book => {
try {
const data = await updateBook({book,
fetchCallback: actions.setBookUpdateState})
actions.updateBook(data)
} catch(error) {
}
},
deleteBook: async id => {
try {
const data = await deleteBook({id,
fetchCallback: actions.setDeleteReadState})
actions.deleteBook(data)
} catch {
}
},
}),
[actions]
)
useEffect(() => {
const controller = abortController.current
actions.readBooks()
return () => {
controller.current.abort()
}
}, [actions])
return {actions}
}
const reducer = (state, {type, payload}) => reducerMap[type](state, payload)
const BooksContainer = props => {
const [state, dispatch] = useReducer(reducer, initialState)
const actions = useMemo(() => bindActionCreators(reducerMap, dispatch), [])
const service = useService({...props, state, actions})
return (
<BooksLayout
{...state}
{...service}
{...props}
/>
)
}
export default BooksContainer
books-layout.js
import React from 'react'
const BooksLayout = ({books, actions, bookReadState, ...props}) => {
return (
<>
{bookReadState === 'loading' ? <div>Loading...</div> :
{books.map(book => (
// UI Logic to display an each book
// button to click to delete
// call actions.deleteBook(id)
)
)
}
}
</>
}
export default BooksLayout
Как вы можете видеть в приведенном выше примере, вы можете контролировать состояние своего приложения в контейнере и не нужно беспокоиться о подключении состояния к каждому компоненту отдельно, как вам нужно делать в Redux.
В приведенном выше примере я сохранил весь код в одном файле для демонстрационных целей, а части кода не были завершены, замените код вашими абстракциями для сетевых вызовов, бизнес-логики и логики пользовательского интерфейса в зависимости от ваших потребностей. Вы можете улучшить этот код, разделив логику в соответствии с вашими потребностями для большего повторного использования в приложении, как предлагает принцип DRY (не повторяйтесь).
Redux отлично подходит и хорошо масштабируется для сложных приложений с глобальным магазином. В этой статье я пытаюсь объяснить, как вы можете использовать использованиередьюсер вместо избыточности для достижения глобального управления состоянием с меньшим количеством кода, и не нужно беспокоиться о добавлении новых пакетов в приложение, и мы можем значительно уменьшить размер пакета приложения.
Пожалуйста, оставьте комментарий и следуйте за мной для получения дополнительных статей.