【问题标题】:React Native Context for changing themes用于更改主题的 React Native Context
【发布时间】:2021-10-25 10:06:24
【问题描述】:

我有一个大约有 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,
    },

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

【问题讨论】:

    标签: javascript reactjs react-native react-hooks


    【解决方案1】:

    您可以将 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',
      }
    }
    

    并使用来自styled-components/nativeThemeProvider 你的App.tsx

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

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

    【讨论】:

      猜你喜欢
      • 2018-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 2018-11-14
      • 1970-01-01
      • 2021-09-27
      相关资源
      最近更新 更多