#javascript #reactjs #react-hooks #use-effect #use-state
Вопрос:
У меня есть состояние, в котором хранится тема текущего приложения, темная или светлая. Я использую хук useEffect для хранения изменений состояния в localStorage, чтобы при обновлении страницы пользователь сохранял предпочитаемую тему, а другой хук useEffect обновлял мое состояние во время начальной загрузки. Однако мое состояние не обновляется во время этой начальной загрузки.
Вещи, которые я пробовал:
- Убедитесь, что эффект использования во время начальной загрузки помещен перед эффектом использования для сохранения состояния темы
- Используйте обещание, чтобы убедиться, что моя функция changeTheme запускается только после изменения состояния при загрузке
- Я зарегистрировал свои результаты, поэтому я знаю, что у localStorage не было никаких проблем с сохранением моих состояний или отслеживанием изменений, но функция setState внутри моего первого крючка useEffect была той, которая не обновила мое состояние должным образом.
Ниже приведены мои коды:
const [theme, setTheme] = useState({}); useEffect(() =gt; { const loadedTheme = JSON.parse(localStorage.getItem(themeStorage)) if (loadedTheme) { console.log("Initial load") console.log(loadedTheme); console.log("Setting theme to localStorage") Promise.resolve() .then(() =gt; { setTheme({ dark: loadedTheme.dark }) }) .then(() =gt; { console.log(theme) }) .then(() =gt; changeTheme()) } }, []) useEffect(() =gt; { localStorage.setItem(themeStorage, JSON.stringify(theme)) console.log("Inside useEffect to save changed theme") console.log(theme) }, [theme]) function changeTheme() { console.log("Inside changeTheme function"); console.log(theme); if (!theme || !theme.dark) { //light turns to dark for (let vars of Object.keys(varTheme)) { document.documentElement.style.setProperty(`--${vars}`, varTheme[vars][0]); } setTheme({ ...theme, dark: true }) } else { for (let vars of Object.keys(varTheme)) { //dark turns to light document.documentElement.style.setProperty(`--${vars}`, varTheme[vars][1]); } setTheme({ ...theme, dark: false }) } }
Комментарии:
1. Если у вас есть опора с изначально переданной темой, можете ли вы установить ее как
const [theme, setTheme] = useState({theme: props.theme});
вне эффекта использования, когда компонент загружается впервые
Ответ №1:
Немного неясно, в чем, по вашему мнению, проблема, но я подозреваю, что вы видите/описываете theme
, что не обновляетесь в первом useEffect
крючке.
Вопрос
Причина этого в том, что состояние реакции считается постоянным и неизменным. В рамках useEffect
обратного theme
вызова значение состояния закрывается в области обратного вызова, и независимо от ожидания или цепочки обещаний значение состояния, закрытое в области, не изменится.
const [theme, setTheme] = useState({}); // lt;-- initial state useEffect(() =gt; { const loadedTheme = JSON.parse(localStorage.getItem(themeStorage)) if (loadedTheme) { console.log("Initial load") console.log(loadedTheme); console.log("Setting theme to localStorage") Promise.resolve() .then(() =gt; { setTheme({ dark: loadedTheme.dark }) }) .then(() =gt; { console.log(theme) }) // lt;-- still initial state .then(() =gt; changeTheme()) } }, []); // lt;-- mounting "instance" of state
Затем вы вызываете changeTheme
его из корпуса, и он также получит доступ к «устаревшему» состоянию корпуса.
Решение
localStorage работает синхронно, поэтому вы можете задать свое начальное состояние с помощью функции инициализатора.
const loadThemeFromStorage = () =gt; { const { dark } = JSON.parse(localStorage.getItem(themeStorage)) ?? {}; return { dark }; }; const [theme, setTheme] = useState(loadThemeFromStorage());
Теперь, когда состояние уже изначально задано, вы можете смело вызывать changeTheme
монтажный useEffect
крюк.
useEffect(() =gt; { console.log("Initial load"); console.log(theme); changeTheme(); }, []); useEffect(() =gt; { localStorage.setItem(themeStorage, JSON.stringify(theme)); console.log("Inside useEffect to save changed theme"); console.log(theme); }, [theme]);
Комментарии:
1. Премного благодарен. Это объяснение имело такой смысл и действительно полезно!