はじめに
styled-componentsのas prop
とforwardedAs
への理解がふわっとしていたため、この機会に整理してみた。
特にforwardedAs
は本家サイトを見ても理解しにくかったので、、、今回ちゃんと整理した。
as propってなに?
v4から追加された機能で、レンダリングする要素のタグを動的に変更できる機能。
styled-componentsでスタイルは使い回して、レンダリングされるタグだけ変更したい場合に利用する。
「ボタンとリンクを別で実装するが、同じスタイルを適用したい」などのユースケースで非常に役立つ。
同じスタイルのコンポーネントを作り分けなくてよくなるのはありがたい。
as propはどうやって書く?
ざっくり書くとこんなかんじ
Hoge = styled.div``; // .Hoge(div)
Piyo = styled(Hoge)``; // .Piyo(Hoge + Piyo)(div)
<Piyo as="h1" /> // .Piyo(Hoge + Piyo)(h1)
Hoge = styled.div``; // .Hoge(div)
Piyo = () => <Hoge />; // .Piyo(() => <Hoge /> + Piyo)(div)
<Piyo as="h1" /> // .Piyo(() => <Hoge /> + Piyo)(h1)
具体的に書くとこんなかんじ
import styled from "styled-components"
import { Link } from "react-router-dom"
// divなど、汎用的なタグで定義しておくと使い回しやすいかも。
const Base = styled.div`
color: red;
`;
// divのまま使ってもOK
<Base>Hello World!</Base>
// spanとして定義
<Base as="span">hoge</Base>
// linkとして定義
<Base as={Link} to="home">hoge</Base>
// 継承も可能
const FontBold = styled(Base)`
font-weight: bold;
`;
<FontBold as="span">hoge</FontBold>
<FontBold as={Link} to="home">hoge</FontBold>
// 継承はこんな書き方もできる
const FontLarge = styled(() => <Base />)`
font-size: large;
`;
forwardedAsってなに?
v4.3から追加された機能で、styled()
にas prop
を渡す場合に利用する機能。
別コンポーネントをラップする場合、forwardedAs
を使用してラップされたコンポーネントにas prop
を渡すことが可能。
※拡張スタイル付きコンポーネントではas prop
を使用しても親スタイルは継承されない。
forwardedAsはどうやって書く?
import styled from "styled-components"
const Cell = styled.td`
background-color: ${props => props.bgColor || "blue"};
`;
const StyledCell = styled(Cell)`
color: red;
`;
const SomeCell = ({ as, ...props}) => {
return <StyledCell forwardedAs={as} {...props} />;
};
const ExtendedCell = styled(SomeCell)`
border: 1px solid red;
`;
render(
<table>
<tr>
<ExtendedCell bgColor="orange" forwardedAs="th">
hoge
</ExtendedCell>
</tr>
</table>
);
まとめ
モヤモヤが少しスッキリした気がする。
あと、複雑なコードを極力書かないで済むような設計にしたいと改めて思った。