Темная тема / с крючками - PullRequest
0 голосов
/ 15 февраля 2020

Здравствуйте, у меня есть собственный хук для определения моей темы

код:

export default function App() {
  const [theme, setTheme] = usePersistedState('light');
  const toggleTheme = () => {
    setTheme(theme.type === 'light' ? 'dark' : 'light');
  };
  return (
    <ThemeProvider theme={theme}>
      <GlobalStyle />
      <div className="App">
        <button onClick={toggleTheme}>a</button>
      </div>
    </ThemeProvider>
  );

и вот мой хук:

import { darkTheme, lightTheme } from '../themes/index';

function usePersistedState(key) {
  const [state, setState] = useState(() => {
    switch (key) {
      case 'dark':
        return darkTheme;
      case 'light':
        return lightTheme;
      default:
        return lightTheme;
    }
  });
  console.log(state);
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(state.type));
  }, [key, state]);

  return [state, setState];
}

export default usePersistedState;

в основном каждый раз, когда мое состояние изменения Я сохраняю его в локальном хранилище, но по какой-то причине он работает только в первый раз

, когда я пытаюсь изменить свою тему во второй раз, я не ввожу свой переключатель

edit:

enter image description here

, как я показываю в gif первый раз, когда я получаю объект, потому что я ввожу свой переключатель, но когда я пытаюсь изменить тему, я получаю только текст, потому что я не ввожу свой переключатель

Ответы [ 2 ]

0 голосов
/ 15 февраля 2020

Я думаю, что вы забыли добавить обертку объекта на toogle с {type: ...}

const toggleTheme = () => {
    setTheme({type: theme.type === 'light' ? 'dark' : 'light'});
};
0 голосов
/ 15 февраля 2020

Аргумент, который вы указываете useState, будет применяться только при первом рендере. На следующих рендерах будет применяться то, что вы предоставляете для функции setState (вы предоставляете 'light' или 'dark' , поэтому значение состояния будет 'light' или 'темный' ) Для вашего варианта использования, в котором вы хотите, чтобы переключение запускало каждое изменение состояния, useReducer является лучшим вариантом, чем useState (на мой взгляд).

import { useReducer } from 'react';
import { darkTheme, lightTheme } from '../themes/index';


function usePersistedState(key) {
  const [state, dispatch] = useReducer(reducer, null, getTheme(key)); // first argument is the reducer function. second argument is the initial state. third argument is an init function (for complex initialization)

  const reducer = (state, action) => { // this will run on every state change (on every dispatch call)
    return getTheme(action.type)();
  }

  const getTheme = (themeType) => () => {
    switch (themeType) {
      case 'dark':
        return darkTheme;
      case 'light':
        return lightTheme;
      default:
        return lightTheme;
    }
  }

  console.log(state);
  useEffect(() => {
    localStorage.setItem('themeType', JSON.stringify(state));
  }, [state]);

  return [state, dispatch];
}

export default usePersistedState;

И от вашего компонента Вы называете диспетчеризацию так:

export default function App() {
  const [theme, setTheme] = usePersistedState('light');
  const toggleTheme = () => {
    setTheme(theme.type === 'light' ? {type: 'dark'} : {type: 'light'});
  };
  return (
    <ThemeProvider theme={theme}>
      <GlobalStyle />
      <div className="App">
        <button onClick={toggleTheme}>a</button>
      </div>
    </ThemeProvider>
  );
...