最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Create a Theme Provider component in React Native - Stack Overflow

programmeradmin7浏览0评论

My application needs a color themes providing and I am trying to implement a Theme Providing ponent 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:

ThemeProvider

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;

App

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 './ponents';

const Stack = createStackNavigator();

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

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

export default App;

Navbar (this ponent 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;

Themes

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

My application needs a color themes providing and I am trying to implement a Theme Providing ponent 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:

ThemeProvider

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;

App

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 './ponents';

const Stack = createStackNavigator();

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

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

export default App;

Navbar (this ponent 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;

Themes

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)',
   },
};
Share Improve this question edited Jul 28, 2020 at 14:54 Amphyx asked Jul 28, 2020 at 13:05 AmphyxAmphyx 7554 gold badges13 silver badges29 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 3

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;

In the child ponent 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>
    );
  }
}

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

发布评论

评论列表(0)

  1. 暂无评论