Help us understand the problem. What is going on with this article?

【React-Native】StyleSheetについて

More than 1 year has passed since last update.

はじめに

React Native では stylesにスタイルを定義してかいているのですが、最近、Webの方でもReact Nativeと同じようにCSS in JSで書きだしてから、React Nativeを書く時にStyleSheet.createを忘れてしまう事案が発生しているので戒めに書きます。
あまり大した内容でなくすみません・・・。

React.js,ReactNativeでもこう書いてしまっていた・・・
const styles = {
  container: {
      marginLeft: '1rem',
      backgroundColor: COLORS.BG_TEAL,
  },
};
class App extends Component {
・・・・
本来ReactNativeではこう書く
const styles = StyleSheet.create({
   container: {
       flex: 1,
       backgroundColor: COLORS.BG_TEAL,
   },
});

class App extends Component {
・・・

そもそもStyleSheet.createは必要?

動作上は不要です。ですので、StyleSheet.createしなくとも動きますし、しない方がプレーンなオブジェクトで便利だったりしますが・・・・・・。

StyleSheet.createした方がいいよ!

StyleSheet.createをすることによって、オブジェクトはidで返るようになります。
これによってパフォーマンスの向上が見込めるので極力はやっておいた方がよいです。

StyleSheet.createする場合
const styles = StyleSheet.create({
  container: {
     flex: 1,
  },
})

console.log(styles.container); // 6 などのプリミティブなnumberが返る
StyleSheet.createしない場合
const styles = {
  container: {
     flex: 1,
  },
};

console.log(styles.container); //ちゃんとオブジェクトが返る。{ flex: 1, }

プリミティブからオブジェクトへの復元

こう・・・、数値で返ってこられるとデバッグの時にこれなんやねんってなって困ることがあります。そこでflattenを使うことで元に戻すことができます。

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

console.log(styles.container); // 6

const _container = StyleSheet.flatten(styles.container);
console.log(_container); //{ flex:1, }

ところが

console.log(Object.getOwnPropertyDescriptor(_container, 'flex')); 
/*
 configurable:false,
 enumerable:true
 value:1
 writable:false
*/

ディスクプリタをみてみるとwritable: falseになっているため書き換えできませんので要注意です。
さらにはconfigurableもfalseなので消すこともできません。

オブジェクトの統合とプロパティの上書き

汎用的なコンポーネントを作成した時には、styleのオーバーライドをしたくなることがあります。
これはradiumと同じ記法でオーバーライドすることで解決できます。
ここでもflattenは活躍します(中身を確認する時は・・・)。

const styles = StyleSheet.create({
    container: {
        flex: 1,
        margin: 30,
    },
    _container: {
        flex: 2,
        padding: 10,
    }
});

console.log(StyleSheet.flatten([styles.container, styles._container]));
// { flex: 2, margin: 30, padding: 10, }

convenience properties

他には便利なプロパティも持っています。

absoluteFill

console.log(StyleSheet.absoluteFill); // 2
console.log(StyleSheet.flatten(StyleSheet.absoluteFill));
/*
  bottom: 0,
  left: 0,
  position: 'absolute',
  right: 0,
  top: 0,
*/

これはプリローダーやモーダルダイアログを出すのに良い感じに動いてくれます。

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    _container: {
        flex: 2,
    },
    overlay: {
        backgroundColor: 'rgba(0, 0, 0, 0.7)',
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
    preloader: {
        backgroundColor: 'rgba(255, 255, 255, 0.8)',
        justifyContent: 'center',
        alignItems: 'center',
        height: 200,
        width: 200,
        borderRadius: 3,
    },
});


const App = (props) => (
        <View style={styles.container}>

            {/* コンテンツ */}
            <Main {...props} />

            {/* オーバーレイ */}
            <View style={StyleSheet.absoluteFill} >
                <View style={styles.overlay} >
                    <View style={styles.preloader}>
                        <Text>ぐるぐる回るやつ</Text>
                    </View>
                </View>
            </View>
        </View>
);

absoluteFillObject

absoluteFillと中身は同じですがこちらはオブジェクトで返ります。

console.log(StyleSheet.absoluteFillObject);
/*
  bottom: 0,
  left: 0,
  position: 'absolute',
  right: 0,
  top: 0,
*/

console.log(
    Object.getOwnPropertyDescriptor(
        StyleSheet.absoluteFillObject, 'top'
    )
);
/*
 configurable:false,
 enumerable:true
 value:object,
 writable:false,
*/

具体的な使い方としては

const styles = StyleSheet.create({
    container: {
        flex: 1,
        margin: 30,
        ...StyleSheet.absoluteFillObject,
    },
});
console.log(StyleSheet.flatten(styles.container));

/*
  bottom: 0,
  left: 0,
  position: 'absolute',
  right: 0,
  top: 0,
  flex: 1,
  margin: 30,
*/

となります。

hairlineWidth

それぞれのプラットフォームでもっとも薄い線を引く時に使える数値が設定されています。

iphone7Plus
console.log(StyleSheet.hairlineWidth); // 0.3333333

ただし、これは固定値ではなくプラットフォーム依存なので、

端末 数値
iphone7Plus 0.333333333
iphone7 0.5
iphone5 0.5
Nexus5x 0.333333333

という感じで異なります。
横幅に依存してるんですかね?

const styles = StyleSheet.create({
   _box: {
      borderColor: '#3C3C3C',
      borderWidth: StyleSheet.hairlineWidth,
   },
});

という感じで利用することができます。

終わりに

以上で終了です!
CSS風なプロパティなんだーぐらいで納得してしまってあまりStyleSheetやStyleSheet.createを使う意義なども考えてこなかったのでいざこうやって勉強し直してみると意外と便利な機能もあるんだなと勉強になりました。
しかし、実際はStyleSheet.createさえ覚えとけばだいたい大丈夫だと思います!
StyleSheet.createルーチンすぎて、忘れやすいですが是非ともお忘れなくつけていただけますと幸いです。

aircloset
「新しい当たり前を作る」を作ることをミッションに、airClosetを開発・運営しています。
http://corp.air-closet.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした