styled-componentsでpropsから値を指定する
styled-components でよくこういう書き方をすることがある。
const StyledInput = styled.input` padding: 20px; width: ${({width}) => width}; `;
以下のように props から width の値を伝搬して値を指定することができる。
<StyledInput width="200px">
あえて言うまでもないが、実際にあたるcssは以下のようになる。
.kXcunH { padding: 20px; width: 200px; }
styled-componentsでpropsの値を指定しないと?
では、以下のようにwidthを指定しなかったらどうなるだろう?
<StyledInput>
正解を言ってしまうと以下になる。
.kXcunH { padding: 20px; }
つまりわざわざ以下のような書き方をしなくていい。
const StyledInput = styled.input` padding: 20px; width: ${({width}) => width ? width : ""}; `;
JavaScriptで undefined は文字列になる
ところで以下をjsで実行するとどうなるかというと、
`width: ${(({width}) => width)({})};`
実は以下のように undefined が文字列になってしまう。
"width: undefined;"
styled-components の仕組み
styled-components はなぜ以下のように undefined になってしまわないのか。
.kXcunH { padding: 20px; width: undefined; }
その理由は styled-components の style の持ち方と生成方法にある。
そもそも styled-components が styled.div`` という書き方をしているが、 JavaScript 的にどのように展開されるのか。
const p = function(){console.log(arguments)} p` width: ${(({width}) => width)}; `
Array と fucntion が返ってくる。
0: ["↵ width: ", ";↵", raw: Array(2)] 1: ({width}) => width
styled-components ではこれを利用し、 宣言されている const Styled = styled.div`` を保持しておき、
宣言されているComponentのコンテキストでfunction実行しながら、 string配列を1つのstring文字列に展開することで最終的な1つの style を生成して HTML に書き出す。
この時、function実行結果が undefined, null などの falsey values だったら書き出さないようにすることで、
.kXcunH { padding: 20px; width: ; }
こういった形式の style が吐き出される。
width: ;
はbrowser側で解釈されずに結果として無視されるので、
最終的に以下のようなstyleとして適用される。
.kXcunH { padding: 20px; }
まとめ
styled-components でよくある書き方ではあるものの、 どうしてこれが動くんだろう、とふと思ったので調べた。
const StyledInput = styled.input` padding: 20px; width: ${({width}) => width}; `;
最近は emotion も流行っているけどどうなんだろう。