vitalets / react-native-extended-stylesheet

Extended StyleSheets for React Native
MIT License
2.93k stars 132 forks source link

Using static theme (change theme without app reload) #47

Closed sm2017 closed 7 years ago

sm2017 commented 7 years ago

1- Is it possible to use static theme and no app reload to theme change? for example when I want to change theme , Just call EStyleSheet.build and forceUpdate again

2- Is dynamic theme need cashing ? IS dynamic theme need stylesheet creation in every render() call?

vitalets commented 7 years ago
  1. So you are talking about dynamic theme change, not static. Calling forceUpdate is not enough, because it will update only root component, but not children (see: https://github.com/facebook/react/issues/3038). UPDATE: forceDeepUpdate() is under discussion https://github.com/facebook/react/issues/7759

  2. Yes, the best way is to pre-built both themes and keep them cached. Please have a look on dynamic theme example and this discussion.

sm2017 commented 7 years ago

In my first question I don't talk about dynamic theme I talk about static theme .

This library is awesome but I have 2 major problem First is orientation change is not supported (https://github.com/vitalets/react-native-extended-stylesheet/issues/9) and Really I need orientation change

Second problem is static theme is very easy to use but dynamic is not as easy as static and also If I have 20+ theme . I MUST prebuild all themes and it need 20x resources Also it is not possible to have live theme change that means user who run App cannot define or modify theme . because prebuild is needed

sm2017 commented 7 years ago

@vitalets any idea?

vitalets commented 7 years ago

Your case is interesting. I agree that caching 20+ themes looks overhead and the best approach is to dynamically build selected theme.

Currently this is not supported in EStyleSheet. But it can be done by changing two places as I described here: https://github.com/vitalets/react-native-extended-stylesheet/issues/22#issuecomment-249249919

I would appreciate I you play with it and share the results. But another important question for me - will it be possible to re-render all components after dynamic theme change. I think it should be checked first. Hope this helps.

sm2017 commented 7 years ago

@vitalets I think we can re-render all components by do following

Assume we have <App/> and it contain whole application , we can surround it with <Theme>

<Theme name="dark" status="loaded">
    <App/>
</Theme>

When we change theme , we change status to loading and when theme is loaded , status is loaded

function Theme (props) {
    if(props.status=="loaded")
      return <View>{props.children}</View>;
    else
      return <Text>Please wait ...</Text>;
}

(i know we lost states , but it is better than reloading application)

sm2017 commented 7 years ago

Any update?

vitalets commented 7 years ago

@sm2017 sorry for delay, lost this thread. Approach looks good to me! So the goal is to re-calculate all styles after theme change - I will try to find time for that.

By the way, could you show the whole example how you see this? For example with <Switch> component that toggles theme.

kevinmartin-jvs commented 2 years ago

My method is in a HOC, but you can adapt it… My solution for recompiling styles when resizing the window is as follows at the onLayout event hide and redisplay the component to take into account the new compiled style

withResponsive.ts

import React, { View, ComponentType, FunctionComponent, useState } from 'react'
import EStyleSheet from 'react-native-extended-stylesheet'

const styles = EStyleSheet.create({
  container: {
    flex: 1,
  },
})

export const withResponsive = (Component: ComponentType): ComponentType => {
  const Responsive: FunctionComponent<unknown> = () => {
    const [show, setShow] = useState<boolean>(true)

    const build = () => {
      setShow(false)
      EStyleSheet.build()
      setShow(true)
    }

    return (
      <View style={styles.container} onLayout={build}>
        {show ? <Component /> : null}
      </View>
    )
  }

  return Responsive
}