React-native-ui-kitten: withStyles doesn't inject styles correctly

Created on 20 Jun 2019  路  10Comments  路  Source: akveo/react-native-ui-kitten

Unexpected Behavior

  • [x ] bug report
  • [ ] feature request

Issue description

Current behavior:
I created a wrapper for TopNavigation to auto display a back button as leftControl if the user can go back in navigationStack.
So in such case, the leftControl would be:

leftControl = (
        <View>
          <TouchableOpacity onPress={() => goBack()}>
            <Feather name="chevron-left" size={32} color="white" />
          </TouchableOpacity>
        </View>
      );

Then I exported my component as following:

export const NavigationBar = withStyles(NavigationBarComponent, (theme: ThemeType) => ({
  color: theme['color-primary-default'],
}));

This should inject a themedStyle Object in my component's props, that has a "color" property, which currently, I'm getting like this:

color: {
 "0": "$",
"1": "c",
"10": "m",
"11": "a",
"12": "r",
"13": "y",
"14": "-",
"15": "5",
"16": "0",
"17": "0",
"2": "o",
 "3": "l",
"4": "o",
"5": "r",
"6": "-",
"7": "p",
"8": "r",
"9": "i",
}

Expected behavior:
"color" property should hold a value of e.g. "#f76a97"

Steps to reproduce:
export a component wrapped with "withStyles" and check the themedStyle prop

Related code:

import React from 'react';
import { SafeAreaView, TouchableOpacity, View } from 'react-native';
import { NavigationScreenProp } from "react-navigation";
import { TopNavigation, TopNavigationProps, Layout, withStyles, ThemedComponentProps, ThemeType } from 'react-native-ui-kitten';
import { Feather } from '@expo/vector-icons';

interface NavigationBarProps extends TopNavigationProps, ThemedComponentProps {
  renderBackButton?: boolean;
  navigation?: NavigationScreenProp<any,any>;
}

const NavigationBarComponent = (props: NavigationBarProps) => {

  // Checking If There Should Be a Back Button As Left Control ------
  let leftControl: React.ReactElement | undefined;
  if (props && props.renderBackButton && props.navigation) {
    const parent: NavigationScreenProp<any, any> | undefined = props.navigation.dangerouslyGetParent();
    if (parent && parent.state && parent.state.index && parent.state.index > 0) {

      console.log(props.themedStyle.color);

      // Create GoBack Function -----
      const goBack: Function = () => {
        if (props.navigation) {
          props.navigation.goBack();
        }
      }

      // Create Back Button, left Control Element -----
      leftControl = (
        <View>
          <TouchableOpacity onPress={() => goBack()}>
            <Feather name="chevron-left" size={32} color="white" />
          </TouchableOpacity>
        </View>
      );
    }
  }

  // Create Default Props -----
  const defaultProps: NavigationBarProps = {
    alignment: "center",
    leftControl: leftControl
  };

  // Return Element -----
  return (
    <Layout level="1">
      <SafeAreaView>
        <TopNavigation {...{...defaultProps, ...props}} />
      </SafeAreaView>
    </Layout>
  );
};

// Export Component With Style Props From Theme ----
export const NavigationBar = withStyles(NavigationBarComponent, (theme: ThemeType) => ({
  color: theme['color-primary-default'],
}));

Other information:

Device: iPhone Xs Max
Device OS: iOS 12.3.1
Expo SDK: 33
Ui-Kitten: 4.0.1
@eva: 1.0.0
typescript: 3.4.5
Help wanted Components

Most helpful comment

@artyorsh
Thanks to the kitten tricks app I was able to track and fix the issue.
It was solved by simply replacing:

export const NavigationBar = withStyles(NavigationBarComponent, (theme: ThemeType) => ({
  color: theme['color-primary-default'],
}));

With

export const NavigationBar = withStyles(NavigationBarComponent, (theme: ThemeType) => ({
  backButton: {
    color: theme['color-primary-default'],
  }
}));

Thank you very much for the quick replies

All 10 comments

Hi @DaniShalash
Thanks for report.
Do you have an application root configured as described in this doc?

Hi @artyorsh ,

Yeah, not exaclty, as I implemented my own logic to change the app theme. However, this behavior still appears even when my app is 100% configured as per the doc you mentioned

Anyway, here's my App.tsx

import React from 'react';
import { StatusBar, View } from 'react-native';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/lib/integration/react';
import { store, persistor } from './store/redux-store';
import { mapping } from '@eva-design/eva';
import { ApplicationProvider } from 'react-native-ui-kitten';
import { Themes } from './themes';
import { ThemeName } from './enums/theme.enum';
import { initApp } from './App.init';
import { AppContainer } from './navigation/navigator';

export default class App extends React.Component<any, any> {

  currentTheme: any = Themes[ThemeName.Light];
  statusBarStyle: 'default' | 'light-content' | 'dark-content' | undefined = 'dark-content';

  constructor(props: any) {
    super(props);
    initApp();
    this.state = store.getState();
    this.subscribeToStoreChanges();
  }

  subscribeToStoreChanges() {
    store.subscribe(() => {
      if (store.getState().theme.themeName != this.state.theme.themeName) {
        this.setState(store.getState());
      }
    });
  }

  checkAppTheme() {
    if (this.state && this.state.theme && this.state.theme.themeName) {
      this.currentTheme = Themes[this.state.theme.themeName];
      switch (this.state.theme.themeName) {
        case ThemeName.Light:
          this.statusBarStyle = 'dark-content';
          break;

        case ThemeName.MidnightBlue:
          this.statusBarStyle = 'light-content';
          break;

        default:
          this.statusBarStyle = 'dark-content';
      }
    } else {
      this.currentTheme = Themes[ThemeName.Light];
      this.statusBarStyle = 'dark-content';
    }
  }

  render(): React.ReactNode {
    this.checkAppTheme();
    return (
      <Provider store={store}>
        <PersistGate loading={<View></View>} persistor={persistor}>
          <ApplicationProvider mapping={mapping} theme={this.currentTheme}>
            <StatusBar animated={true} barStyle={this.statusBarStyle} />
            <AppContainer />
          </ApplicationProvider>
        </PersistGate>
      </Provider>
    );
  }
}

With an example you've provided I'm not pretty sure you're correctly exporting your themes.
I need to run your example in case this error occurs only in one component (NavigationBar)

btw you can take a look at kitten tricks app and see our practical usage to resolve this faster. This app also uses both light and dark themes and every custom component is created using withStyles

@artyorsh
You can disregard theme={this.currentTheme} in ApplicationProvider, and replace it with theme={lightTheme}, Where lightTheme is imported as following:
import { light as lightTheme } from '@eva-design/eva'

It'll produce the same behavior.

@artyorsh
Thanks to the kitten tricks app I was able to track and fix the issue.
It was solved by simply replacing:

export const NavigationBar = withStyles(NavigationBarComponent, (theme: ThemeType) => ({
  color: theme['color-primary-default'],
}));

With

export const NavigationBar = withStyles(NavigationBarComponent, (theme: ThemeType) => ({
  backButton: {
    color: theme['color-primary-default'],
  }
}));

Thank you very much for the quick replies

yeah, sorry, there was a lot of code to determine the problem quickly
glad to help :)

@DaniShalash are the docs going to be updated?

Can someone explain as to why does this happen? Nesting the style inside another object fixes the issue? How?

@YashGadle take more attention on the @DaniShalash answer. withStyles arrow function should return an object with nested objects (not single style entries), just like you do when using StyleSheet

It works because it iterates through the keys of object you return

Was this page helpful?
0 / 5 - 0 ratings

Related issues

simonsankar picture simonsankar  路  3Comments

sobiso picture sobiso  路  3Comments

chamatt picture chamatt  路  3Comments

evangunawan picture evangunawan  路  3Comments

sarmadkung picture sarmadkung  路  3Comments