Не уверен, правильно ли я использую setState, потому что мое состояние не обновляется во время начальной загрузки

#javascript #reactjs #react-hooks #use-effect #use-state

Вопрос:

У меня есть состояние, в котором хранится тема текущего приложения, темная или светлая. Я использую хук useEffect для хранения изменений состояния в localStorage, чтобы при обновлении страницы пользователь сохранял предпочитаемую тему, а другой хук useEffect обновлял мое состояние во время начальной загрузки. Однако мое состояние не обновляется во время этой начальной загрузки.

Вещи, которые я пробовал:

  1. Убедитесь, что эффект использования во время начальной загрузки помещен перед эффектом использования для сохранения состояния темы
  2. Используйте обещание, чтобы убедиться, что моя функция changeTheme запускается только после изменения состояния при загрузке
  3. Я зарегистрировал свои результаты, поэтому я знаю, что у 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. Премного благодарен. Это объяснение имело такой смысл и действительно полезно!