Closed5

contextだったものをpropsにするときにそのまま値を引き継ぐとどうなるかの思考実験

terrierscriptterrierscript
  • 課題:Contextで引き渡していた値をそのままPropsにしてflatに渡すと、集約コンポーネントみたいなものにおいてPropsの名前がぶつかってしまうんじゃなかろうか?
    • -> contextの値をflatにせずそのまま引き渡したらどうなるだろうか?
terrierscriptterrierscript

例えばこんな具合のContextが利用されていたとすると

const useCounter = () => {
  const [count, setCounter] = useState(0)
  const increment = () => setCounter( v => v + 1)
  const decrement = () => setCounter( v => v - 1)
  return {count ,increment, decrement} 
}

const CounterContext = createContext(null)

const CounterProvider = ({children}) => {
  const value = useCounter()
  return <CounterContext.Provider value={value}>
    {children}
  </CounterContext.Provider>
}

↓こういう感じになるんだろうか?


import React, { createContext, FC, useState } from 'react'

// Contextに使われていたcustom hooks。値と操作関数のencapselation
const useCounter = () => {
  const [count, setCounter] = useState(0)
  const increment = () => setCounter( v => v + 1)
  const decrement = () => setCounter( v => v - 1)
  return {count ,increment, decrement} 
}


// この名前はなんとすべきか。contextに習えばvalueか。
type CounterValues = ReturnType<typeof useCounter>
type CounterServiceProps = {
  counterValues: CounterValues
}
const CounterPreview: FC<CounterServiceProps> = ({ counterValues }) =>  <div>{counterValues.count}</div>
const CounterIncrementButton: FC<CounterServiceProps> = ({ counterValues}) =>  <div>
  <button onClick={() => counterValues.increment()}>+</button>
</div>
const CounterDecrementButton: FC<CounterServiceProps> = ({ counterValues}) => <div>
  <button onClick={() => counterValues.decrement()}>-</button>
</div>
const CounterButtons: FC<CounterServiceProps> = (props) =>  <div style={{flexDirection:"column"}}>
  <CounterIncrementButton {...props} />
  <CounterDecrementButton {...props} />
</div>

export default function Home() {
  const counterValues = useCounter() 
  return (
    <div>
      <CounterPreview counterValues={counterValues}/>
      <CounterButtons counterValues={counterValues}/>
    </div>
  )
}
terrierscriptterrierscript

いろんなコンテキスト(であったもの)が増えてきたらこういう風になっていくはず

export default function Home() {
  const counterValues = useCounter()
  const timeValue = useMyTimes()
  const props = { counterValues, timeValue}
  return (
    <div>
      <TimeForm {...props}/>
      <ConterForm {...props} />
      <Preview {...props} />
    </div>
  )
}
terrierscriptterrierscript

肌感

  • 慣れれば多分アリな気がする
  • 全部ゴリっと渡してしまうので、大味にはなる。
    • 本当は枝葉のコンポーネントはvalue全部渡さず必要な分だけを渡すようにしたほうがテスタビリティが上がる。
  • 機能的には問題は多分無い気がする
このスクラップは2021/03/20にクローズされました