Reactで各コンポ―ネントで実施している共通処理をCompositionで外だししてしまう

Reactでコンポーネントをたくさん作っていると各コンポーネントに共通処理が出てきてうっとおしい場合がありませんか？

例)初回レンダリング時にログを出力する
例）特定の属性の値(valueとする)が設定されているかをrequired属性の有無によってチェックするかを切り替える

オブジェクト指向だとこういった共通する処理は親クラスで実装し、親を継承した子クラスに独自の処理を記載するということが行われます。

ReactではComposition機能が用意されているのでそれを使って実装したいと思います。

・CustomComponentAには１つの入力があり、required付加時には未入力の場合は必須エラー
・CustomComponentBには２つの入力があり、required付加時にはどちらも未入力の場合は必須エラー


App.tsxで以下を呼び出してます。
CustomComponentA　必須
CustomComponentB　必須
CustomComponentB　任意
```App.tsx
import { useState } from 'react'
import CustomComponentA from './CustomComponentA'
import CustomComponentB from './CustomComponentB'

function App() {
  const [value,setValue] = useState<string>('')
  const [address,setAddress] = useState<string>();

  const onChange = (e:ChangeEvent<HTMLInputElement>) =>{
    setValue(e.target.value)
  }

  return (
    <div className="App">
      <CustomComponentA required/>
      <CustomComponentB required/>
      <CustomComponentB />
    </div>
  )
}

export default App

```

共通処理を記述するCompositionです
```SampleComposition.tsx
import React, { ReactNode, useEffect, useState } from 'react'

type propsType = {
  children:ReactNode,
  childprop?:any,
  value?:string
}

const SampleComposition = (props:propsType) => {
  const [errormessage,setErrormessage] = useState('');
  const [value,setValue] = useState(props.value);

  useEffect(()=>{
    //初回時にログを出すとか・・
    console.log('LOG:I am parent.');
  },[])
  useEffect(()=>{
    setValue(props.value);
  },[props.value])

  const onBlur = () =>{
    //blur時に必須チェックするとか・・・
    if(!!props.childprop && !!props.childprop.required){
      console.log('LOG:Child is required!!');

      if(!value){
        setErrormessage('★必須入力エラー(value未設定）')
      }else{
        setErrormessage('')
      }
    }
  }
  
  return (
    <fieldset onBlur={onBlur}>
      <legend>Parent</legend>
      {props.children}
      <p>{errormessage}</p>
    </fieldset>
  )
}

export default SampleComposition;
```

CustomComponentAのポイントはここではrequiredの実装はしていません。
※微妙な点：
・Compositionコンポーネントと呼出しコンポーネントの結合度が高い気がする。共通化を主眼においてしかたないとするか？
・汎用性を持たせる観点からSampleCompositionのchildpropをanyにしてしまっている点でtypescriptの恩恵にあずかれない。
　※これは共通のtypeやらinterfaceやらを定義すればよいかな？

```CustomComponentA.tsx
import React, { ChangeEvent, ChangeEventHandler, useEffect, useState } from 'react'
import SampleComposition from "./SampleComposition";

const CustomComponentA = (props: any) => {
  const [value, setValue] = useState(props.value);

  useEffect(() => {
    console.log('LOG:I am CustomComponentA.');
  }, [])

  const onChange = (e:ChangeEvent<HTMLInputElement>) =>{
    setValue(e.target.value)
  }

  return (
    <>
      <SampleComposition childprop={props} value={value}>
        <input value={value} onChange={onChange}/>
      </SampleComposition>
    </>
  )
}

export default CustomComponentA;
```

```CustomComponentB.tsx
import React, { ChangeEvent, ChangeEventHandler, useEffect, useState } from 'react'
import SampleComposition from "./SampleComposition";

const CustomComponentB = (props: any) => {
  const [valueA, setValueA] = useState('');
  const [valueB, setValueB] = useState('');

  useEffect(() => {
    console.log('LOG:I am CustomComponentB.');
  }, [])

  const onChangeA = (e:ChangeEvent<HTMLInputElement>) =>{
    setValueA(e.target.value)
  }
  const onChangeB = (e:ChangeEvent<HTMLInputElement>) =>{
    setValueB(e.target.value)
  }

  return (
    <>
      <SampleComposition childprop={props} value={valueA + valueB}>
        <input value={valueA} onChange={onChangeA}/>
        <input value={valueB} onChange={onChangeB}/>
      </SampleComposition>
    </>
  )
}

export default CustomComponentB;
```

実行結果
blur時に無事エラーメッセージが出力されました。
子コンポーネントにrequiredを定義せずchildpropとして渡すことでかなり力技ですが実装はできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653035/736b8da1-14d0-c405-72ea-ec10c0b96f75.png)

入力時にはメッセージが消えていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653035/d664eb4d-af15-d89e-7e26-e232094ce6a0.png)


まぁCompositionも使い方色々ですかね。

以上