在 React Native 中创建一个 Theme Provider 组件

在 React Native 中创建一个 Theme Provider 组件

问题描述:

我的应用程序需要提供颜色主题,我正在尝试使用 React 上下文实现主题提供组件,但它不起作用.我不知道如何从主题提供程序的上下文中获取 theme 道具对象,以及如何调用作为主题提供程序状态的 updateTheme 函数?这是我的代码:

My application needs a color themes providing and I am trying to implement a Theme Providing component using a React Context, but it does not work. I can't figure out how to get the theme prop object from the Theme Provider's Context and how can I call the updateTheme function that is state of Theme Provider? This is my code:

主题提供者

import React from "react";
import { LightTheme, DarkTheme } from '../themes'

const Context = React.createContext();

export class ThemeProvider extends React.Component {
  
  state = {
    theme: LightTheme,
    updateTheme: (theme) => {
      this.setState({ theme: theme })
    }
  }

  render() {
    const { theme } = this.state
    return (
      <Context.Provider value={this.state} theme={theme} >
        { this.props.children }
      </Context.Provider>
    )
  }
}

export default ThemeProvider;

应用

import React from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
} from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { HomeScreen } from './screens';
import { NavBar, ThemeProvider } from './components';

const Stack = createStackNavigator();

const App: () => React$Node = () => {

  return (
    <ThemeProvider>
      <NavigationContainer>
        <StatusBar barStyle="dark-content" />
        <NavBar />
        <Stack.Navigator
          screenOptions={{
            headerShown: false
          }}
        >
          <Stack.Screen name="Home" component={HomeScreen} />
        </Stack.Navigator>
      </NavigationContainer>
    </ThemeProvider>
  );
};

export default App;

Navbar(此组件必须从 ThemeProvider 获取 theme 道具以更改其颜色)

Navbar (this component have to get the theme prop from the ThemeProvider to change it's color)

import React from 'react';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
} from 'react-native';

import { Container, Header, Left, Body, Right, Button, Title } from 'native-base';
import Icon from 'react-native-vector-icons/MaterialIcons';
import { Layout } from '../constants';

class NavBar extends React.Component {
  
  static contextType = ThemeProvider;
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Header>
        <Left>
          <Button transparent>
            <Icon name='add' size={Layout.navIconSize} />
          </Button>
        </Left>
        <Body>
          <Title>Header</Title>
        </Body>
        <Right>
          <Button transparent>
            <Icon name='alarm' size={Layout.navIconSize} />
          </Button>
        </Right>
      </Header>
    )
  }
}

export default NavBar;

主题

export const LightTheme = {
   dark: false,
   colors: {
      primary: 'rgb(255, 45, 85)',
      background: 'rgb(242, 242, 242)',
      card: 'rgb(255, 255, 255)',
      text: 'rgb(28, 28, 30)',
      border: 'rgb(199, 199, 204)',
      notification: 'rgb(255, 69, 58)',
   }
}

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)',
   },
};

你已经完成了主要部分,你只需要做一些小改动就可以让它工作.

You have done the major part, you just have to do some minor changes to get it to work.

首先为了更改上下文的值,您必须导出上下文.然后访问消费者.

First In order to change the values of a context you will have to export the context. Then access the consumer.

import React from "react";
import { LightTheme, DarkTheme } from '../themes'

export const Context = React.createContext();

export class ThemeProvider extends React.Component {
  
  state = {
    theme: LightTheme,
    updateTheme: (theme) => {
      this.setState({ theme: theme })
    }
  }

  render() {
    const { theme } = this.state
    return (
      <Context.Provider value={this.state} theme={theme} >
        { this.props.children }
      </Context.Provider>
    )
  }
}

export default ThemeProvider;

在您的情况下是 NavBar 的子组件中,您必须导入它并使用使用者进行更新导入如下上下文(您的实际路径可能会有所不同)

In the child component which is the NavBar in your case, you will have to import it and use the consumer to do updates Import the context like below (Your actual paths may vary)

import ThemeProvider, { Context } from './ThemeProvider';


class NavBar extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Context.Consumer>
        {({ theme, updateTheme }) => (
          <Header>
            <Left>
              <Button
                title="Update Theme"
                onPress={() => updateTheme(theme.dark ? LightTheme : DarkTheme)}
              />
              <Button transparent>
                <Icon name="add" size={Layout.navIconSize} />
              </Button>
            </Left>
            <Body>
              <Title>Header</Title>
            </Body>
            <Right>
              <Button transparent>
                <Icon name="alarm" size={Layout.navIconSize} />
              </Button>
            </Right>
          </Header>
        )}
      </Context.Consumer>
    );
  }
}

{({ 主题,更新主题 }) =>(上面的行提供了对上下文和 updateTheme 中主题值的访问.你可以试试代码.

{({ theme, updateTheme }) => ( The above line provides access to your theme value in the context and updateTheme. You can try out the code.