【问题标题】:React Native - What is the benefit of using StyleSheet vs a plain object?React Native - 使用 StyleSheet 与普通对象相比有什么好处?
【发布时间】:2016-12-21 21:12:17
【问题描述】:

使用StyleSheet.create() 与普通对象相比究竟有什么好处?

const styles = StyleSheet.create({
  container: {
    flex: 1
  }
}

对比

const styles = {
  container: {
    flex: 1
  }
}

【问题讨论】:

  • 我获得了对属性的 VSCode 智能感知支持。这就是好处。

标签: react-native


【解决方案1】:

没有任何好处。期间。

误区 1:StyleSheet 性能更高

StyleSheet 和在render 之外声明的对象之间绝对没有性能差异(如果您每次都在render 中创建一个新对象,情况会有所不同)。性能差异是一个神话。

神话的起源很可能是因为 React Native 团队试图这样做,但他们没有成功。在官方文档中您找不到任何关于性能的信息:https://facebook.github.io/react-native/docs/stylesheet.html,而源代码声明“尚未实现”:https://github.com/facebook/react-native/blob/master/Libraries/StyleSheet/StyleSheet.js#L207

误区 2:StyleSheet 在编译时验证样式对象

这不是真的。纯 JavaScript 无法在编译时验证对象。

两件事:

  • 它会在运行时验证,但在将样式对象传递给组件时也会验证。没有区别。
  • 它确实会在编译时验证如果您使用的是 Flow 或 TypeScript,但是一旦您将对象作为样式属性传递给组件,或者您正确地键入提示对象(如下所示),它也会验证。也没有区别。
const containerStyle: ViewStyle = {
   ...
}

【讨论】:

  • 是的。也许混淆来自他们文档的早期版本,暗示他们最终将通过 id 引用样式。这在 0.59 文档中没有提到。
  • THX 揭秘。但问题是开放的 - 有什么用?
  • 所以使用 StyleSheet 完全……没用?
  • 我的测试表明它确实在运行时验证而无需传递给组件,例如StyleSheet.create( {x:{flex: "1"}} ) 将在运行时失败,打字稿在编译时对此进行检查。
【解决方案2】:

直接引用 React native 的 StyleSheet.js 的评论部分

代码质量:

  • 通过将样式从渲染函数中移开,您可以使代码更易于理解。

  • 为样式命名是为渲染函数中的低级组件添加意义的好方法。

性能:

  • 从样式对象制作样式表可以通过 ID 引用它,而不是每次都创建新的样式对象。

  • 它还允许样式只通过桥发送一次。所有后续使用都将引用一个 id(尚未实现)。

StyleSheet 也会验证您的样式表内容。因此,任何样式属性不正确的错误都会在编译时显示,而不是在实际实现 StyleSheet 时显示。

【讨论】:

  • 前三个要点与 OP 将样式对象声明为渲染函数之外的 const 的技术无关。
  • 当我阅读解释时,我仍然看不出StyleSheet.create({styles...}) 比{styles...} 更好/更快。代码同样干净,而且您还使用命名而不是内联。谁能解释一下?
  • StyleSheet 在编译时提供验证
  • 投反对票。不要在你的答案中加入不相关的信息(“通过将样式从渲染函数中移开”等)。
  • 投反对票,OP 的问题是 StyleSheet.create 和普通对象之间的区别,而不是内联与类外的常量
【解决方案3】:

接受的答案不是 OP 问题的答案。

问题不在于内联样式和类外的const 之间的区别,而是为什么我们应该使用StyleSheet.create 而不是普通对象。

经过一番研究,我发现了以下内容(如果您有任何信息,请更新)。 StyleSheet.create的优点应该如下:

  1. 验证样式
  2. 更好的性能,因为它会创建样式到 ID 的映射,然后使用此 ID 在内部进行引用,而不是每次都创建一个新对象。因此,即使更新设备的过程也更快,因为您不会每次都发送所有新对象。

【讨论】:

  • 这些都是神话。检查我的答案。
  • 如果我在类之外定义样式对象(甚至作为类属性),它将被创建一次(或每个实例一次)。再次创建的相同对象仅与内部函数相关。
  • 是的,对于 const,但类属性不行。静态类属性是的。
【解决方案4】:

过去人们认为使用 StyleSheet 性能更高,并且 出于这个原因,RN 团队在 0.57 版之前是recommended,但现在不再推荐正确指出在another answer 中回答这个问题。

RN documentation 现在推荐 StyleSheet 的原因如下,尽管我认为这些原因同样适用于在渲染函数之外创建的普通对象:

  • 通过将样式从渲染功能中移开,您正在制作 代码更容易理解。
  • 为样式命名是为底层添加意义的好方法 渲染函数中的组件。

那么我认为 使用 StyleSheet 而非普通对象可能带来的好处是什么?

1) 尽管有相反的说法,但我在 RN v0.59.10 上的测试表明您在调用StyleSheet.create() 时确实得到了一些验证,并且打字稿(可能还有流)也会在编译时报告错误.即使没有编译时检查,我认为在样式用于渲染之前对样式进行运行时验证仍然是有益的,尤其是在可以有条件地渲染使用这些样式的组件的情况下。这将允许在无需测试所有渲染场景的情况下检测此类错误。

2) 鉴于 StyleSheet 是 由 RN 团队推荐的,他们可能仍然希望在未来使用 StyleSheet 来提高性能,并且他们可能还会考虑其他可能的改进,例如:

3) 当前的StyleSheet.create() 运行时验证很有用,但有点受限。它似乎仅限于使用流或打字稿进行的类型检查,所以会选择flex: "1" 或borderStyle: "rubbish",但不是width: "rubbish",因为这可能是一个百分比字符串。 RN 团队将来可能会通过检查百分比字符串或范围限制等内容来改进此类验证,或者您可以将 StyleSheet.create() 包装在自己的函数中以进行更广泛的验证。

4) 通过使用 StyleSheet,您或许可以更轻松地过渡到提供更多功能的第三方替代方案/扩展,例如 react-native-extended-stylesheet。

【讨论】:

    【解决方案5】:

    我没有发现 StyleSheet 和普通对象之间有任何区别,除了 TypeScript 中的输入验证。

    例如,这个(注意打字差异):

    import { View, Text, Image, StyleSheet } from 'react-native';
    import logo from './logo.svg';
    
    export default class App extends Component {
      render() {
        return (
          <View style={styles.someViewStyle}>
            <Text style={styles.someTextStyle}>Text Here</Text>
            <Image style={styles.someImageStyle} source={logo} />
          </View>
        );
      }
    }
    
    const styles: StyleSheet.create({
      someViewStyle: {
        backgroundColor: '#FFF',
        padding: 10,
      },
      someTextStyle: {
        fontSize: 24,
        fontWeight: '600',
      },
      someImageStyle: {
        height: 50,
        width: 100,
      },
    });
    

    等于:

    import { View, Text, Image, ViewStyle, TextStyle, ImageStyle } from 'react-native';
    import logo from './logo.svg';
    
    export default class App extends Component {
      render() {
        return (
          <View style={styles.someViewStyle}>
            <Text style={styles.someTextStyle}>Text Here</Text>
            <Image style={styles.someImageStyle} source={logo} />
          </View>
        );
      }
    }
    
    const styles: {
      someViewStyle: ViewStyle;
      someTextStyle: TextStyle;
      someImageStyle: ImageStyle;
    } = {
      someViewStyle: {
        backgroundColor: '#FFF',
        padding: 10,
      },
      someTextStyle: {
        fontSize: 24,
        fontWeight: '600',
      },
      someImageStyle: {
        height: 50,
        width: 100,
      },
    };
    

    【讨论】:

    • 感谢您提供 TypeScript 示例。
    【解决方案6】:

    所以,今天,2021 年 9 月,在阅读了所有答案并进行了一些研究后,我创建了一个关于使用 Stylesheet 而不是普通对象的摘要。

    1. 基于React Documentation,当复杂性开始增加时,您应该使用样式表。

    style 属性可以是一个普通的旧 JavaScript 对象。这就是我们通常使用的示例代码。 随着组件变得越来越复杂,使用 StyleSheet.create 在一个地方定义多个样式通常会更简洁。

    1. 在模拟器中,使用样式表时会显示ERROR,使用普通对象时只会显示WARNING。
    2. 根据第 2 项,它看起来在编译时有一些验证。 (很多人说这是一个神话)
    3. 如果你以后需要迁移第三方库,比如react-native-extended-stylesheet,如果你使用样式表,会更容易。
    4. 您有一些methods 和properties 可以促进发展。例如,属性StyleSheet.absoluteFill 将执行position: 'absolute', left: 0, right: 0, top: 0, bottom: 0,或者方法compose() 将允许您组合两种样式,覆盖它。

    P.S.:性能答案似乎是一个神话。

    我的意见?

    根据第 2 和第 5 项,转到样式表而不是普通对象。

    【讨论】:

      【解决方案7】:

      只有当全局变量 __DEV__ 设置为 true 时,通过 StyleSheet.create 创建您的样式才会通过验证(或者在 Android 或 IOS 模拟器中运行时,请参阅 React Native DEV and PROD variables)

      函数source的代码很简单:

      create < +S: ____Styles_Internal > (obj: S): $ReadOnly < S > {
        // TODO: This should return S as the return type. But first,
        // we need to codemod all the callsites that are typing this
        // return value as a number (even though it was opaque).
        if (__DEV__) {
          for (const key in obj) {
            StyleSheetValidation.validateStyle(key, obj);
            if (obj[key]) {
              Object.freeze(obj[key]);
            }
          }
        }
        return obj;
      }
      

      我会推荐使用它,因为它会在开发过程中执行运行时验证,还会冻结对象。

      【讨论】:

        猜你喜欢
        • 2010-11-25
        • 1970-01-01
        • 2017-03-10
        • 1970-01-01
        • 2020-01-01
        • 2020-01-14
        • 2010-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多