Приветствую вас, разработчики!
Одним из очень популярных способов, используемых разработчиками для обмена состоянием между компонентами, является Context API React, и мы не можем отрицать, что он полезен и уже давно решает наши проблемы.
Но давайте уделим немного времени и обратим внимание на его собственную документацию:
Прежде чем использовать Context
Context в основном используется, когда некоторые данные должны быть доступны многим компонентам на разных уровнях вложенности. Применять его следует осторожно, поскольку он затрудняет повторное использование компонентов.
Однако, по моим ощущениям, одна из частей, которая была полностью пропущена, является последней:
Применяйте его экономно, потому что это усложняет повторное использование компонентов.
Я видел много проектов — в том числе и мой — которые сильно полагались на Context для обмена состоянием. И это вызывало множество проблем: от снижения опыта разработчиков до невосполнимого управления состоянием.
Вот только одна из проблем, и, скорее всего, самая распространенная для меня: что если вам нужно получить доступ к определенному состоянию за пределами сферы React? Решить эту проблему не совсем просто, и даже создание обходного решения противоречит интуиции.
Давайте выберем другой фрагмент из того, что говорится в документации Context:
[…] когда некоторые данные должны быть доступны многим компонентам на разных уровнях вложенности.
Вложенность — это еще один момент, о котором вы должны беспокоиться при использовании Context. В большой кодовой базе легко заблудиться и не знать, почему ваше состояние не является точным — возможно, вы вызываете Context на уровне, на котором он недоступен; кто знает?
Вот некоторые из причин, по которым существует суперсостояние. Чтобы сделать управление состоянием простым и кристально ясным.
На практике
Использование Context в приложении с темной/светлой темой — вот один из способов добиться этого:
import { createContext, useContext } from 'react'
export const ThemeContext = createContext({
theme: 'light',
setTheme: () => {}
})
export function App() {
const [theme, setTheme] = useState('light')
return (
<ThemeContext.Provider
value={{
theme,
setTheme: (newTheme) => setTheme(newTheme)
}}
>
<Button />
</ThemeContext.Provider>
)
}
function Button() {
const themeCtx = useContext(UserContext);
return (
<button
onClick={() => {
themeCtx.setTheme(themeCtx.theme === 'dark' ? 'light' : ' dark')
}}
>
Toggle theme
</button>
)
}
Теперь, с суперсостоянием:
import { superstate } from '@superstate/core'
import { useSuperState } from '@superstate/core'
export const theme = superstate('light')
export function App() {
return <Button />
}
function Button() {
useSuperState(theme)
return (
<button
onClick={() => {
theme.set(prev => prev === 'dark' ? 'light' : 'dark')
}}
>
Toggle theme
</button>
)
}
Заключение
Как видно из приведенного выше примера, superstate сократил количество кода, необходимого для достижения того же решения. Но не это главное; самое приятное заключается в том, что у вас есть более гладкий, более дружелюбный API, который не заботится об иерархии или вложенности, что приводит к более чистому коду и большему удобству для разработчиков. Кроме того, вы заметили, что вам не пришлось создавать метод set
самостоятельно? 🪄
Учитывая это, может быть, в следующем штате стоит рассмотреть superstate как вариант управления состояниями? Я почти уверен, что вам это понравится.