1

I have a state variable that holds the name of the theme (Light, Dark, etc).

In my render function, I would like to use the appropriate style for my components based on the theme. If the DarkTheme is being used on the "mainHeader" class for example, the style of the View component would be something like this:

<View style = {DarkTheme.mainHeader}>
</View>

If the theme is LightTheme, then it should be:

<View style = {LightTheme.mainHeader}>
</View>

For efficiency's sake, I thought that if I put the name of the theme in a state variable, I could do something like this:

<View style = {{this.state.theme + '.mainHeader'}}>
</View>

Expecting the evaluation of the theme variable to return either LightTheme.mainHeader or DarkTheme.mainHeader.

But I am wrong, this does not work. Is there anyway I can make this work?

kyle
  • 691
  • 1
  • 7
  • 17
user3604212
  • 35
  • 1
  • 9

3 Answers3

2

You can also use a ternary operator inside of the render() to set classes based on the theme that you would reference with this.state.theme.

const classes = this.state.theme === 'dark' ? style.dark : style.light;

Then in your element you would use it like such with className:

<View className={classes}>

Here's a quick jsfiddle example. Change the state option from light to dark and the background will change: https://jsfiddle.net/3516s2vg/

Edit: Ok so if you are wanting to use more then one theme here, one option could be to use a switch statement to specify the specific class. I'm not a react expert so I'm not even sure if this would be the best way to go about this. The switch would also go inside of the render().

let classes = '';

switch(this.state.theme) {
  case 'dark':
    classes = style.dark;
    break;
  case 'light':
    classes = style.light;
    break;
  case 'other':
    classes = style.other;
    break;
  default:
    classes = style.dark;
}

And again to use it you would do <View className={classes}>.

justDan
  • 2,302
  • 5
  • 20
  • 29
  • Yes, this is what I am currently doing. It works fine with 2 themes but when you try more than 2, the ternary operator quickly becomes ugly. – user3604212 Feb 10 '19 at 02:17
  • Ah yeah if you have more than 2 options I can see that. Let me think for a minute. – justDan Feb 10 '19 at 02:18
1

You could either:

  1. put the actual theme object on state or
  2. write a statement in the style attribute that evaluates the string on state.theme and returns the actual object. (haven't tried this one but I believe it would work)

But yeah you can't compose an object name like that with concatenation, or at least not easily.

Here's a great answer about inline styles in React: React.js inline style best practices (1st answer from @chantastic)

Worth mentioning, I did something like this on my portfolio page which uses theme provider and styled components, and you can see the code for that functionality here: https://github.com/xezian/xezian/blob/master/client/src/components/Page/Page.js

JSONaLeo
  • 416
  • 6
  • 11
  • I tried number 1 and preferred not go that route. Number 2 is a good suggestion. I used a ternary operator and that works fine for 2 themes and becomes painful for more than that. I'll take a look at the links you sent. Many thanks. – user3604212 Feb 10 '19 at 02:08
1

Instead of storing name of the theme in state, try storing the style value.

this.state = {
   theme: DarkTheme.mainHeader 
}

And directly use the state value

<View style = {this.state.theme}>
</View>
Sriram
  • 626
  • 7
  • 11
  • Yes, I contemplating doing this but I would have to create so many state variables for each component and I am trying to not overload state because it takes time to render all these components. – user3604212 Feb 10 '19 at 02:07