React で slot みたいなことしたい
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ React のコンポーネントで WebComponents の slot みたいなことがしたい
◆ サポートされてないので children を手動で分割してそれぞれを配置
◆ children 以外の props を使うと楽に済むが使う側の見た目がイマイチ
◆ children をオブジェクトにしてプロパティで分割することもできる
◆ サポートされてないので children を手動で分割してそれぞれを配置
◆ children 以外の props を使うと楽に済むが使う側の見た目がイマイチ
◆ children をオブジェクトにしてプロパティで分割することもできる
ライブラリを見てると 子要素がそれぞれの場所に配置されていたりします
WebComponent でいう slot に当たるものです
こういうので left と right を別のところに配置したいです
React にはそういう機能はないので children としてまとめて受け取ったものから自分で分離が必要です
一応 children は props のひとつでしかないので children ではなく 他の props にしてこういうことをすれば React 標準で簡単にできます
left と right が混在せずに分けられてるという点では良い気もします
ですが 子要素ではなく属性の中に長くなるようなものを書くのは抵抗もあります
HTML のように子要素に書きたいです
みたいな 1 行だけでコンポーネント選択するようなものであれば抵抗はないのですけどね
一応 children は任意の型にできるので オブジェクトを渡してこれも有効です
見た目だと こっちのほうが好きかもしれません
この例では ありそうな header/body に分けてみてます
WebComponent でいう slot に当たるものです
<Component>
<div slot="left">1</div>
<div slot="left">2</div>
<div slot="right">3</div>
<div slot="left">4</div>
<div slot="right">5</div>
</Component>
こういうので left と right を別のところに配置したいです
React にはそういう機能はないので children としてまとめて受け取ったものから自分で分離が必要です
一応 children は props のひとつでしかないので children ではなく 他の props にしてこういうことをすれば React 標準で簡単にできます
<Component
left={
<>
<div>left item1</div>
<div>left item2</div>
</>
}
right={
<>
<div>right item1</div>
<div>right item2</div>
</>
}
/>
const Component = ({ left, right }) => {
return (
<div style={{display: "flex", gap: 50}}>
<div>{left}</div>
<div>{right}</div>
</div>
)
}
left と right が混在せずに分けられてるという点では良い気もします
ですが 子要素ではなく属性の中に長くなるようなものを書くのは抵抗もあります
HTML のように子要素に書きたいです
<Component
element={<Foo value={value} />}
/>
みたいな 1 行だけでコンポーネント選択するようなものであれば抵抗はないのですけどね
一応 children は任意の型にできるので オブジェクトを渡してこれも有効です
<Component>
{{
left: (
<>
<div>left item1</div>
<div>left item2</div>
</>
),
right: (
<>
<div>right item1</div>
<div>right item2</div>
</>
),
}}
</Component>
const Component = ({ children }) => {
return (
<div style={{display: "flex", gap: 50}}>
<div>{children.left}</div>
<div>{children.right}</div>
</div>
)
}
見た目だと こっちのほうが好きかもしれません
children を分離
受け取る側のコンポーネントの面倒が増えますが children に直接配置されたものを使う場合はこれで動きますこの例では ありそうな header/body に分けてみてます
const Component = ({ children }) => {
const filter = fn =>
children
? Array.isArray(children)
? children.filter(fn)
: [children].filter(fn)
: null
const header = filter(x => x.props.slot === "header")
const body = filter(x => x.props.slot === "body")
return (
<div>
<div style={{borderBottom: "1px solid black"}}>
{header}
</div>
<div>
{body}
</div>
</div>
)
}
const App = () => {
return (
<Component>
<div slot="header">header1</div>
<div slot="body">body1</div>
<div slot="header">header2</div>
<div slot="body">body2</div>
</Component>
)
}