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

IT技术 javascript reactjs react-native
2021-05-11 11:20:41

我的应用程序需要提供颜色主题,我正在尝试使用 React Context 实现主题提供组件,但它不起作用。我不知道如何theme从 Theme Provider 的 Context 中获取prop 对象,以及如何调用处于updateThemeTheme Provider 状态函数?这是我的代码:

主题提供者

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;

导航栏(此组件必须theme从 ThemeProvider获取props才能更改其颜色)

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)',
   },
};
1个回答

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

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

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 的子组件中,您必须导入它并使用使用者进行更新导入如下所示的上下文(您的实际路径可能会有所不同)

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

{({ theme, updateTheme }) => ( 上面这行提供了在上下文和 updateTheme 中访问您的主题值。您可以尝试代码。