首页 > 解决方案 > 用于更改主题的 React Native Context

问题描述

我有一个大约有 6 个屏幕的应用程序,并且想为它们编写一个一致的主题管理器。我觉得我大部分时间都在那里,但我在最后一点挣扎。我想要的是有一个ThemesScreen包含主题列表,单击每个主题都会动态更改它,我可以看到单击按钮确实会更改名称,但我正在努力让它通过沿着。这是我的ThemeManager.js

import React, { createContext, useState } from "react"; 

import { current } from "../Styles/themes";

export const ThemeContext = React.createContext();

export const ThemeProvider = ({ children }) =>{
    //light, dark
    const[theme, setTheme] = React.useState("light");

    const toggleTheme = () =>{
        if(theme === 'light'){
            setTheme("dark");

        }
        else{
            setTheme("light");
        }
        console.log(theme)
    }

    return (
        <ThemeContext.Provider value={{ theme, toggleTheme }}>
          {children}
        </ThemeContext.Provider>
    )
}

这是我的ThemesScreen.js

import React, { useContext } from 'react';
import { Text, ScrollView, StyleSheet, Alert } from 'react-native';

import { RowItem, RowSeparator } from '../Styles/RowItem';

import ThemeProvider, { ThemeContext } from '../utils/ThemeManager';

function ThemeScreen(){ 
    const theme = useContext(ThemeContext)
    return (
        <ThemeContext.Consumer>
            <ScrollView style={styles.row}>
                <RowItem
                    title="Light theme"
                    onPress={toggleTheme}/>
                <RowSeparator />
                <RowItem 
                    title="Dark Theme"
                    onPress={() => alert('Dark!')}/>
                <RowSeparator />
                <RowItem
                    title="Material Blue"
                    onPress={() => alert('Material blue!')}/>
            </ScrollView>   
        </ThemeContext.Consumer>
    )
}

const styles = StyleSheet.create({
    row: {
        backgroundColor: theme.background,
      },
});

export default ThemeScreen

这是我的 Themes.js

export const LightTheme = {
    dark: false,
    colors: {
       primary: 'rgb(255, 45, 85)',
       background: 'f5f5f5',
       card: 'rgb(255, 255, 255)',
       text: '#333333',
       border: 'rgba(175, 47, 47, .75)',
       notification: 'rgba(175, 47, 47, .35)',
    }
 }
 
 export const DarkTheme = {
    dark: true,
    colors: {
       primary: 'rgb(255, 45, 85)',
       background: 'rgb(0, 0, 0)',
       card: 'rgb(255, 255, 255)',
       text: 'rgb(28, 28, 30)',
       border: 'rgb(199, 199, 204)',
       notification: 'rgb(255, 69, 58)',
    },
 };

 const current = LightTheme

 export { current }

我最初的想法是,我可以将当​​前所选主题的名称设置为当前,然后执行以下代码之类的操作,因为我有很多不同的屏幕可以节省我的时间。

import { current } from './styles/themes.js;
...
const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: current.background,
        paddingTop: 25,
    },

但我不太确定如何做到这一点,或者这是否可行。我将不胜感激任何和所有的建议!另外,如果有更好的方法可以做到这一点,请告诉我。

标签: javascriptreactjsreact-nativereact-hooks

解决方案


您可以将您的移动styles到组件的主体中:


import { RowItem, RowSeparator } from '../Styles/RowItem';

import ThemeProvider, { ThemeContext } from '../utils/ThemeManager';

function ThemeScreen(){ 
    const theme = useContext(ThemeContext)

    const styles = StyleSheet.create({
      row: {
        backgroundColor: theme.background,
        },
    });
    return (
        <ThemeContext.Consumer>
            <ScrollView style={styles.row}>
                <RowItem
                    title="Light theme"
                    onPress={toggleTheme}/>
                <RowSeparator />
                <RowItem 
                    title="Dark Theme"
                    onPress={() => alert('Dark!')}/>
                <RowSeparator />
                <RowItem
                    title="Material Blue"
                    onPress={() => alert('Material blue!')}/>
            </ScrollView>   
        </ThemeContext.Consumer>
    )
}


export default ThemeScreen

我还建议记住您的切换器和上下文以提高性能。

对于您的react-native应用程序主题,您是否考虑过使用styled-components

我们在我们的跨平台项目中使用它,并添加创建主题化应用程序所需的一切。

它还会将 UX 逻辑从您的组件中分离出来,现在您需要从上下文中手动导入主题,并且您没有像您期望的那样用于样式化组件的 API。

yarn add styled-components

创建一个样式化的组件:

const Container = styled.View(({ theme }) => ({
  backgroundColor: theme.colors.white,
}))

添加./theme.js

export const theme = {
  colors: {
    white: '#ffffff',
  }
}

并使用您ThemeProvider的:styled-components/nativeApp.tsx

+  import { ThemeProvider } from 'styled-components/native'
+  import { theme } from './theme'
-  <App />
+  <ThemeProvider theme={theme}><App /></ThemeProvider>

仍然可以使用useTheme()钩子从组件中访问主题,但我建议您尽量保持样式表逻辑最大程度分离。


推荐阅读