【问题标题】:React Native (or React) listen to the style changes for the dark mode in separate ts modulesReact Native(或 React)在单独的 ts 模块中监听暗模式的样式变化
【发布时间】:2023-03-17 04:18:01
【问题描述】:

目标:在 React Native 应用程序中实现 暗模式。 系统简介: 文件结构:

  • 个人资料.ts
  • ProfileCss.ts
  • constants.ts

在我的应用程序中,为了将样式与组件分开,我将它们移动到 .ts 文件中并作为模块导出。 StyleCss.ts 示例:

import {StyleSheet} from 'react-native';
import {Window, FixedCSS, hsize, wsize} from '../../entities/constants';
    
export default StyleSheet.create({
    loading: {
        backgroundColor: FixedCSS.Colors.MainBackgroundColor,
    }
    ...
});

所有与样式相关的常量值都存储在 constants.ts 中,例如 Colors、LineHeights 等。constants.ts 还包含一个名为 FixedCSS 具有静态属性:

export class FixedCSS {
    static isDark = true;

    static Colors = {
        // Main Colors
        RootColor: FixedCSS.isDark ? '#FF6666' : '#FF6666',
        MainBackgroundColor: FixedCSS.isDark ? '#050505' : '#FFFFFF',
        ...
    }
    ...
}
FixedCSS 的

isDark 属性应该在 Profile.ts 中的 Switch 组件的帮助下进行更改

<Switch
    value={darkMode}
    onValueChange={value => {
        this.setState({darkMode: value});
    }}
/>

问题:如何更改 FixedCSS 类中的 isDark 属性,使其影响组件的外观。最有问题的方面是 StyleCSS.ts 文件不会反映 FixedCSS 类中 isDark 属性的更改,因为它们仅在创建 js 包时导出一次。

【问题讨论】:

    标签: javascript reactjs typescript react-native rendering


    【解决方案1】:

    更改类的static 属性不会触发重新呈现它应该的方式。这需要以某种方式使用state。我推荐一个主题Context。您可以使用一个上下文或使用单独的上下文来控制 isDarkMode 并提供 CSS,这就是我在这里所做的。

    为了只导出一次值但使该值保持最新,导出的值可以是函数而不是常量。我正在使固定 CSS 成为 isDark 的函数,而单个组件样式成为 FixedCSS 的函数。

    constants.ts

    export const createFixedCSS = (isDark: boolean) => ({
      isDark,
      Colors: {
        // Main Colors
        RootColor: isDark ? "#FF6666" : "#FF6666",
        MainBackgroundColor: isDark ? "#050505" : "#FFFFFF"
        ...
      }
      ...
    });
    
    export type FixedCSS = ReturnType<typeof createFixedCSS>;
    
    export const IS_DARK_DEFAULT = false;
    

    cssContext.ts

    // context to provide the FixedCSS object, which also includes isDark
    const FixedCSSContext = createContext(createFixedCSS(IS_DARK_DEFAULT));
    
    // context to provide a function for switching modes
    // type Dispatch<SetStateAction<T>> allows for setting based on previous value
    type SetModeContextValue = Dispatch<SetStateAction<boolean>>;
    
    // needs an initial value that fits the type signature
    const SetModeContext = createContext<SetModeContextValue>(() => {
        throw new Error(
          "cannot set `isDark` outside of a `DarkModeContext` Provider"
        );
    });
    
    // combine both contexts into one Provider component
    export const CSSProvider: FC<{}> = ({ children }) => {
      // store the isDark state
      const [isDark, setIsDark] = useState(IS_DARK_DEFAULT);
    
      // update the FixedCSS when isDark changes
      // I'm not sure if memoizing is actually necessary here?
      const FixedCSS = useMemo(() => createFixedCSS(isDark), [isDark]);
    
      return (
        <SetModeContext.Provider value={setIsDark}>
          <FixedCSSContext.Provider value={FixedCSS}>
            {children}
          </FixedCSSContext.Provider>
        </SetModeContext.Provider>
      );
    };
    
    // I prefer to export the hooks rather than the contexts themselves
    export const useFixedCSS = () => useContext(FixedCSSContext);
    export const useSetMode = () => useContext(SetModeContext);
    
    // helper hook for `StyleCss.ts` files
    // takes the makeStyles factory function and turns it into a style object by accessing the  FixedCSS context
    export const useStyleFactory = <T extends StyleSheet.NamedStyles<T>>(
      factory: (css: FixedCSS) => T
    ): T => {
      const FixedCSS = useFixedCSS();
      return useMemo(() => factory(FixedCSS), [FixedCSS, factory]);
    };
    

    ProfileCss.ts

    export const makeStyles = (FixedCSS: FixedCSS) => StyleSheet.create({
        loading: {
            backgroundColor: FixedCSS.Colors.MainBackgroundColor,
        }
    });
    

    Profile.ts

    const DarkModeToggle = () => {
      // access isDark from global FixedCSS
      const {isDark} = useFixedCSS();
      
      // access update callback
      const setIsDark = useSetMode();
    
      return (
        <Switch
          value={isDark}
          onValueChange={setIsDark}
        />
      )
    }
    
    const Profile = () => {
    
      // pass the imported `makeStyles` to the hook and get stateful styles object
      const styles = useStyleFactory(makeStyles);
    
      return (
        <View>
          <DarkModeToggle/>
          <View style={styles.loading}/>
        </View>
      );
    };
    

    CodeSandbox Demo(全部在一个文件中)

    【讨论】:

      猜你喜欢
      • 2020-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多