如何使用usememo钩子在React Native App中持久保存数据

时间:2019-11-22 18:59:42

标签: javascript react-native react-hooks react-context

我正在用React native编写应用程序,遇到一个问题-该应用程序将具有多个屏幕(我使用react-navigation和react-navigation-tabs)以及由以下两个主题管理的两种颜色主题(浅色和深色)上下文和挂钩。我要实现的是应用程序要记住的所选主题(浅色主题将设置为默认主题,并且在切换为暗色后,仍应应用该应用程序并返回暗色主题)。

编辑#2:昨天的一个回答(由于某种原因而消失了)建议使用redux和本地存储,因此我正在编辑下面的段落以阐明情况。

最简单的方法是使用同步存储/ localStorage(我已经有使用本地存储的应用版本),但是我在网上发现的一个教程为此目的使用了用户备注挂钩,尽管它应该可以运行,不是(至少就我而言),而且我也不知道为什么...

下面的我的App.js文件:

imports ...

const TabNavigator = createBottomTabNavigator({
  Home: Home,
  List: List,
});

const App = createAppContainer(TabNavigator);

export default () => (
  <ThemeProvider>
    <App />
  </ThemeProvider>

ThemeContext.js文件:

imports ...

export const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
    const [colors, setColors] = useState(themes.lightTheme) //setting light theme as default

    const value = useMemo(
      () => ({
          colors,
          setColors,
      }),
      [colors, setColors],
    );

  return (
    <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
  );
}

和Home.js文件,带有在主题之间切换的按钮:

imports ...

export const Home = () => {
  const { colors, setColors } = useContext(ThemeContext);

  const toggleTheme = () => {
    if (colors.type === 'light') {
      setColors(themes.darkTheme);
      } else {
      setColors(themes.lightTheme);
      }
  }

  return (
    <>
      <View style={{...styles.mainView, backgroundColor: colors.backgroundColor }}>
        <Text style={{...styles.mainText, color: colors.color}}>Hello Native World</Text>
        <Button title='toggle theme' onPress={toggleTheme} />
      </View>
    </>
  )
}

const styles = StyleSheet.create({
  mainView: {
    paddingTop: 40,
    display: 'flex',
    alignItems: 'center',
  },
  mainText: {
    fontSize: 40,
    fontWeight: 'bold',
  },
});

1 个答案:

答案 0 :(得分:1)

您需要更改的密钥文件是您的上下文文件:

export const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
    const [colors, setColors] = useState(themes.lightTheme) //setting light theme as default

    const value = useMemo(
      () => ({
          colors,
          setColors,
      }),
      [colors, setColors],
    );

  return (
    <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
  );
}

我不太了解您为什么使用useMemo,但我会保留。乍一看,我会说不需要它,但我不知道您的应用程序。您想要的是这样的:

import AsyncStorage from '@react-community/async-storage'

export const ThemeContext = createContext()

export function usePersistedState(key, initialState) {
  const [state, setState] = useState(() => {})

  useEffect(() => {
    async function getAndSetInitialState() {
      const persistedState = await AsyncStorage.getItem(key)
      if (persistedState) {
        setState(JSON.parse(persistedState))
      } else if (typeof initialState === 'function') {
        return setState(initialState())
      } else {
        return setState(initialState)
      }
    }
    getAndSetInitialState()
  }, [key])

  function setPersistedState(value) {
    AsyncStorage.setItem(key, JSON.stringify(value))
    setState(value)
  }

  return [state, setPersistedState]
}

export const ThemeProvider = ({ children }) => {
  const [colors, setColors] = usePersistedState("your_storage_key", themes.lightTheme) //setting light theme as default

  const value = useMemo(
    () => ({
      colors,
      setColors,
    }),
    [colors, setColors]
  )

  return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
}

我可能会错过一些极端情况,但是这样,您的应用程序将从存储中加载状态并将其状态保存到存储中。

编辑:我不确定useMemo有什么帮助,AsyncStorage是最简单的imo解决方案。