通过响应本机元素更改主题无法正常工作? [英] changing theme with react native elements not working?

查看:111
本文介绍了通过响应本机元素更改主题无法正常工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在处理本机元素.我想对我的应用程序实施暗模式,但由于某种原因,当上下文中的状态更改时,<ThemeProvider/>中的主题道具无法更改.

I've been working with react native elements. I want to implement a dark mode to my app but for some reason I cant get the theme prop in <ThemeProvider/> to change when my state in my context changes.

这是我的上下文,其中有我的darkTheme和lightTheme对象.我还有一个使用useState的lightThemeState,因此我可以从子组件中设置该状态.

Here is my context where I have my darkTheme and lightTheme object. I also have a lightThemeState using useState so I can set that state from a child component.

import React, { createContext, useState, useEffect } from "react";
import { AsyncStorage } from "react-native";

import { ThemeProvider } from "react-native-elements";
import lightTheme from "../themes/light";
import darkTheme from "../themes/dark";

export const ThemeModeContext = createContext();

export const ThemeContextProvider = (props) => {
  const [lightThemeState, setLightThemeState] = useState(true);

  const saveThemeState = async () => {
    if (lightThemeState) {
      await AsyncStorage.removeItem("lightThemeState");
    } else {
      await AsyncStorage.setItem(
        "lightThemeState",
        JSON.stringify(lightThemeState)
      );
    }
  };

  const getThemeState = async () => {
    currentMode = await AsyncStorage.getItem("lightThemeState");

    if (currentMode) {
      setLightThemeState(JSON.parse(currentMode));
    }
  };

  useEffect(() => {
    saveThemeState();
  }, [lightThemeState]);

  useEffect(() => {
    getThemeState();
  }, []);

  const currentTheme = lightThemeState ? lightTheme : darkTheme;

  console.log("LIGHT THEME STATE", lightThemeState); 
// When I log this after I used the setLigthThemeState in a child component. It gives the correct state ie true or false.
  console.log("COLOR OF THE THEMES BACKGROUND", currentTheme.colors.background);
// This also gives the correct background for the theme that is the "currentTheme" depending on the state. So this far, everything is correct.

  return (
    <ThemeModeContext.Provider value={[lightThemeState, setLightThemeState]}>
      <ThemeProvider theme={currentTheme}>{props.children}</ThemeProvider>
    </ThemeModeContext.Provider>
  );
};

export default ThemeContextProvider;

因为我有另一个上下文可用于其他逻辑.我将<ThemeContextProvider/>与其他上下文<JourneyContextProvider/>结合在一起.像这样:

Because I have another context that I use for other logic. I combine <ThemeContextProvider/> with my other context <JourneyContextProvider/>. Like so:

import React from "react";
import ThemeContextProvider from "./themeStore";
import JourneyContextProvider from "./journeyStore";

export const CombinedStoreProvider = (props) => {
  return (
    <JourneyContextProvider>
      <ThemeContextProvider>{props.children}</ThemeContextProvider>
    </JourneyContextProvider>
  );
};

export default CombinedStoreProvider;

然后,最后我将整个应用程序包装在<CombinedStoreProvider/>中.像这样.

Then finally i wrap the whole app in my <CombinedStoreProvider/>. Like so.

import React from "react";
import { SafeAreaView } from "react-native";

import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs";

import Icon from "react-native-vector-icons/Ionicons";

import MoreScreenfrom "./src/screens/MoreModal";
import CombinedStoreProvider from "./store/combinedStore";

const TabNavigator = createMaterialBottomTabNavigator(
  {
    MoreScreen: {
      screen: MoreScreen,
      navigationOptions: {
        title: "More",
        tabBarIcon: ({ tintColor }) => (
          <SafeAreaView>
            <Icon style={[{ color: tintColor }]} size={25} name={"ios-more"} />
          </SafeAreaView>
        ),
      },
    },
  },
  {
    theme: ({ darkTheme }) => console.log(darkTheme),
    barStyleDark: {
      backgroundColor: darkTheme.colors.background,
    },
    barStyleLight: {
      backgroundColor: lightTheme.colors.background,
    },
    shifting: false,
    labeled: true,
    initialRouteName: "MoreScreen",
    activeColor: "#E4DC93",
    inactiveColor: "#fff",
    barStyle: { backgroundColor: "transparent", height: 80, paddingTop: 10 },
  }
);

const AllRoutes = createSwitchNavigator(
  {
    PersonalSettings: {
      title: "Personal Settings",
      screen: PersonalSettings,
      header: ({ goBack }) => ({
        left: (
          <Icon
            name={"chevron-left"}
            onPress={() => {
              goBack();
            }}
          />
        ),
      }),
    },
    Tabs: {
      screen: TabNavigator,
    },
  },
  {
    initialRouteName: "Tabs",
  }
);

const AppContainer = createAppContainer(AllRoutes);

export default App = () => {
  return (
    <CombinedStoreProvider>
      <AppContainer />
    </CombinedStoreProvider>
  );
};

这是我的子组件,可以在上下文中切换lightThemeState.但是,即使在ThemeContextProvider中一切看起来都很棒(我在控制台上记录了状态和背景色,并且它们成功更改了主题).但是在此组件中,我仅获得了上一个主题.即使在切换lightThemeState时此子组件重新渲染,也没有任何变化.我知道这是因为在切换主题之后,该组件中的控制台日志再次记录下来,但是日志显示了以前的主题颜色.这是子组件:

And here is my child component where I toggle the lightThemeState in my context. But even though everything looks great in ThemeContextProvider (I console log the state and background color and they have succesfully changed the theme). But in this component I only get the previous theme. Like nothing changed even though this child component rerenders when I toggle the lightThemeState. I know this because the console log in this component logs again after i toggle the theme but the logs show the previous theme colors. Here is the child component:

import React, { useContext, useState } from "react";
import { StyleSheet, View, Text } from "react-native";
import { LayoutView, ContainerView } from "../../components/styles";
import { ThemeModeContext } from "../../../store/themeStore";
import { Card, ListItem, Avatar, ThemeContext } from "react-native-elements";

import CustomButton from "../../components/CustomButton";

const INITIAL_PERSONAL_INFO_STATE = {
  name: "",
  username: "",
  profileImage: "",
  favoriteDestinations: [],
};

const MoreModal = (props) => {
  const [personalInfo, setPersonalInfo] = useState(INITIAL_PERSONAL_INFO_STATE);

  const [lightThemeState, setLightThemeState] = useContext(ThemeModeContext);
  const { theme } = useContext(ThemeContext);
  const { navigate } = props.navigation;

  const primaryColor = theme.colors.background;

  console.log("COLOR IN COMPONENT", primaryColor);
// The color is from the previous theme and even thou the state has changed in the state below
  console.log("LIGHT THEME STATE IN COMPONENT", lightThemeState);

  return (
    <LayoutView primaryColor={theme.colors.background}>
      <ContainerView>
        <View>
        </View>
        <Card
          title={"Settings"}
        >
          <ListItem
            title="Light mode"
            switch={{
              value: lightThemeState,
              onValueChange: (value) => setLightThemeState(value), 
// Here is where I set lighThemeState to false in my context

            }}
            bottomDivider
        </Card>
      </ContainerView>
      <CustomButton title={"Sign in"}></CustomButton>
    </LayoutView>
  );
};

export default MoreModal;

您问的darkTheme和lightTheme也许有问题吗?不,如果我将状态从true更改为false并重新加载应用程序.有用. 主题在<ThemeProvider theme={currentTheme}/>中不会更新.有人可以解释为什么吗?

Maybe there is something wrong with the darkTheme and lightTheme you ask? No, if I changs the state from true to false and reload the app. It works. Somehow the theme doesnt update in the <ThemeProvider theme={currentTheme}/>. Can someone explain why?

推荐答案

您不能使用React Native Elements动态更改主题.不幸的是,这在任何地方都没有记录-这很重要,因为RNE的大多数用户会假设他们可以在运行时动态更改整个主题(嗯,我做到了).

You can't change the the theme dynamically with React Native Elements. Unfortunately this isn't documented anywhere - it's an important point since most users of RNE will assume they can change the entire theme dynamically during runtime (well, I did).

React Native Elements github上有几个封闭的问题提到了这一点. 例如此问题(2019年1月)之一开发人员说:

There's a couple of closed issues on React Native Elements github that mention this. For example this issue (Jan 2019) one of the devs stated:

目前无法实现. ThemeProvider不允许对其属性进行运行时更改.这是因为对ThemeProvider道具的更改将触发树下所有组件的重新渲染.

Currently right now this isn't possible. The ThemeProvider doesn't allow runtime changes to it's props. This is because changes to the props of the ThemeProvider will trigger a rerender for all components under the tree.

更新: 您 可以 动态更改主题,但必须使用

UPDATE: You can change the theme dynamically, but you have to use the withTheme HOC that React Native Elements provides (e.g. calling the updateTheme function provided by withTheme). There's a little bit of extra wiring but it's doable. You can wrap the HOC at near the top level so the theme update propagates to all children.

这篇关于通过响应本机元素更改主题无法正常工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆