styled-componentsでラップした複数の子要素に同じpropsを同時に渡す
タイトルの通りです。あるコンポーネント内で配下にある全ての子要素(styled-componentsでラップされたものであるとします)に共通したpropsを渡す場合のやり方の話です。愚直に書いていたらキリがなく最悪なコードが出来上がります。
結論
styled-components/ThemeContext
を使おう。
import { ThemeContext } from 'styled-components'
具体例
まずこんな感じの複雑なコンポーネント Component
が存在しているとします。多くのコンポーネントやDOMを内包していますが、それらは全てstyled-componentsでラップされています。
const A = styled.div` /* ... */ ${props => props.value} /* ... */ ` const B = styled.div` /* ... */ ${props => props.value} /* ... */ ` const C = styled.div` /* ... */ ${props => props.value} /* ... */ ` // ... const Z = styled.div` /* ... */ ${props => props.value} /* ... */ ` const Component = () => { return ( <Container> <A /> <B /> <C /> {/* ... */} <Z /> </Container> ) }
ここで、全ての(あるいは殆どの)内包したコンポーネントで value
という共通した値を使いまわしたいとします。(この value
は useContext
などで更に上層から受け取ったものとします)
そんな時に、こんなこと↓なんてやていられません。
const Component = () => { return ( <Container> <A value={value} /> <B value={value} /> <C value={value} /> {/* ... */} <Z value={value} /> </Container> ) }
こういうときは ThemeContext
を使いましょう、一発で解決します。
const Component = () => { return ( <ThemeContext.Provider value={/* 任意の値 */}> <Container> <A /> <B /> <C /> {/* ... */} <Z /> </Container> </ThemeContext.Provider> ) }
ただし、注意点として呼び出す際のpropsのプロパティがtheme
になるので、既に違うプロパティで定義してる場合は修正しましょう。
- ${props => props.value} + ${props => props.theme}
また当然ではありますがtheme
にオブジェクトを渡すことでpropsを一層ラップした状態でこれまで通りに値を扱えます。
interface Attrs { // 渡したいpropsの型定義 } const A = styled.div` /* ... */ ${({ theme: props }: { theme: Attrs }) => props.aaa} ${({ theme: props }: { theme: Attrs }) => props.bbb} ${({ theme: props }: { theme: Attrs }) => props.ccc} /* ... */ ` const Component = () => { const attrs: Attrs = { /* ... */ } return ( <ThemeContext.Provider value={attrs}> <Container> <A /> <B /> <C /> ... <Z /> </Container> </ThemeContext.Provider> ) }
以上です。