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

javascript - how to create context for theme with reactjs? - Stack Overflow

programmeradmin1浏览0评论

I need to create a context to apply dark or light theme in repositories. There will be no change of themes by button or something like that, I'll just set the theme and that's it

for now, I have context like this

import { createContext } from "react";
import { light } from './themes';

export const ThemeContext = createContext(light);

export default ThemeContext;

and my app

import { light, dark } from './themes';


<ThemeContext.Provider value={light}> // or dark, depending on the project
   <App />   
 </ThemeContext.Provider> 
);

that way is not working, how can I apply the theme?

I need to create a context to apply dark or light theme in repositories. There will be no change of themes by button or something like that, I'll just set the theme and that's it

for now, I have context like this

import { createContext } from "react";
import { light } from './themes';

export const ThemeContext = createContext(light);

export default ThemeContext;

and my app

import { light, dark } from './themes';


<ThemeContext.Provider value={light}> // or dark, depending on the project
   <App />   
 </ThemeContext.Provider> 
);

that way is not working, how can I apply the theme?

Share Improve this question asked Feb 3, 2022 at 1:44 ryan Mostryan Most 411 silver badge3 bronze badges 1
  • 2 If you want to access the value of the ThemeContextProvider you need to either use ThemeContext.Consumer in class ponents, or the const lightTheme = useContext(ThemeContext) and access all the values from the lightTheme variable – Ameer Commented Feb 3, 2022 at 1:57
Add a ment  | 

1 Answer 1

Reset to default 4

You've created a provider which makes its value available to every child in the tree. But, any child that wants to use that value needs to consume it.

The patterns for how to consume the context are different for class ponents VS. function ponents but the basic principle is the same: you need tell your child ponent how to get the theme value from the context.

Consuming Context from a function ponent

For function ponents, the simplest way is with the useContext hook (example copied straight from the hooks docs):

function ThemedButton() {
  const theme = useContext(ThemeContext);
  
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

A helpful pattern with a custom hook

The above works, but there's a really nice pattern where you can wrap the consumer in a custom hook which you'd call something like useTheme (I first saw this pattern here).

// Step 1
const ThemeContext = React.createContext(undefined)

// Step 2
function ThemeProvider({children}) {
  return (
    <ThemeContext.Provider value={light}>
      {children}
    </ThemeContext.Provider>
  )
}

// Step 3
function useTheme() {
  const context = React.useContext(ThemeContext)
  
  if (context === undefined) {
    throw new Error('useTheme must be used within a ThemeProvider')
  }
  return context
}

export {ThemeProvider, useTheme}

Step 1 - Creates the context. You've already done this in your example.

Step 2 - Creates the provider. You've used a provider in "my app".

Step 3 - This is what's new. It creates a custom hook that checks that the provider is accessible (throwing an error if not) and then returns the value from the provider.

You then use the hook like this:

function ThemedButton() {
  const theme = useTheme()
  
  return <Text color={theme.textColor}>Some text</Text>
}

There are a few benefits to this pattern:

  1. You only need to import the hook, useTheme, in the ponents that consume the theme. If you use useContext directly, you need to import the context and the useContext hook.
  2. The throw new Error('...') line will warn you if you accidentally try to use useTheme somewhere in the ponent tree that doesn't have access to the provider.

Consuming Context with a class ponent

The examples with class ponents are a little long and more nuanced, so I'll remend using the docs for the details of how to do that. But, one approach is like this:

<ThemeContext.Consumer>
  {value => <ThemedButton theme={value} />
</ThemeContext.Consumer>
发布评论

评论列表(0)

  1. 暂无评论