◆ React.memo だと children などに JSX の要素が入るとメモできない
  ◆ 毎回新たにオブジェクトを作る
  ◆ props の比較が毎回異なる
◆ メモできるようにするには children などをさらにメモする必要あり
◆ それなら React.memo せず useMemo で全体をメモするほうが良い

コンポーネントの不要なレンダリングを減らすのは React.memo でも useMemo でもできますが React.memo のほうが コンポーネント内の書き方を変える必要がなくて見た目的には好きです
それにフックを書く関数の前半に JSX で DOM 定義があるよりも最後の return の中に全てあったが方がわかりやすいです

React.memo でコンポーネントをラップすると そのコンポーネントに渡される予定の props の中身をそれぞれ比較して 違いがなければそのコンポーネントのレンダリングをスキップしてくれます

<!DOCTYPE html>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const { useState, useMemo } = React

const Component1 = ({ name, value }) => {
console.log(name, "1")

return (
<div>{name} {value}</div>
)
}

const Component2 = ({ name, value }) => {
console.log(name, "2")

return (
<div>{name} {value}</div>
)
}

const Component1M = React.memo(Component1)
const Component2M = React.memo(Component2)

const App = () => {
const [c1, setC1] = useState(0)
const [c2, setC2] = useState(0)

return (
<div>
<button onClick={() => setC1(c1 + 1)}>c1:{c1}</button>
<button onClick={() => setC2(c2 + 1)}>c2:{c2}</button>
<Component1 value={c1} name="A" />
<Component2 value={c2} name="B" />
<Component1M value={c1} name="C" />
<Component2M value={c2} name="D" />
</div>
)
}

ReactDOM.render(
<App/>,
document.getElementById("root")
)
</script>
<div id="root"></div>

c1 のボタンを押すと A, B, C が出力されます
memo されてる Component2M は value と name に変化がないので関数が呼び出されていません
Component1M は value に変化があるので関数が呼び出されます
Component2 は value に変化はないですが memo してないので毎回呼び出されます

c2 のボタンを押すと A, B, D が出力されます

この仕組みを見ていて思ったのですが children って props の比較でどう扱われるのでしょうか?
例えばこういう JSX です

<Component>
<div>A</div>
</Component>

常に props に変化はなく固定ですが div で作られるオブジェクトは毎回異なる気がします
試してみました

<!DOCTYPE html>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const { useState, useMemo } = React

const Component = ({ children, value }) => {
console.log("render")

return (
<div>
<div>{value}</div>
<div>{children}</div>
</div>
)
}

const ComponentM = React.memo(Component)

const App = () => {
const [c, setC] = useState(0)

return (
<div>
<button onClick={() => setC(c + 1)}>c:{c}</button>
<ComponentM>
<div>text</div>
</ComponentM>
</div>
)
}

ReactDOM.render(
<App/>,
document.getElementById("root")
)
</script>
<div id="root"></div>

ボタンを押すと毎回 render というログが出力されています
やはり props 比較で毎回異なると扱われてるようです

対処するには children を毎回同じにする必要があります
方法は useState, useMemo, useRef など色々考えられますが children だけ memo しておくのはなんか微妙な感じがします

const App = () => {
const [c, setC] = useState(0)
const component_children = useMemo(() => <div>text</div>, [])

return (
<div>
<button onClick={() => setC(c + 1)}>c:{c}</button>
<ComponentM>
{component_children}
</ComponentM>
</div>
)
}

children 部分が別のところに移動しますし ComponentM みたいなコンポーネントを複数使いたいときにわかりづらくなります
また ComponentM 自体が React.memo を使ったものなので 2 回メモが必要になってます

こうするくらいなら最初から Component 全体を useMemo で保持して React.memo は使わないほうが良い気がします

<!DOCTYPE html>
<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const { useState, useMemo } = React

const Component = ({ children, value }) => {
console.log("render")

return (
<div>
<div>{value}</div>
<div>{children}</div>
</div>
)
}

const App = () => {
const [c, setC] = useState(0)
const component = useMemo(() => (
<Component>
<div>text</div>
</Component>
), [])

return (
<div>
<button onClick={() => setC(c + 1)}>c:{c}</button>
{component}
</div>
)
}

ReactDOM.render(
<App/>,
document.getElementById("root")
)
</script>
<div id="root"></div>

その他の props を渡したり children の JSX 内で変数値を使うなら依存配列に追加します

const component = useMemo(() => (
<Component value={value}>
<div>{text}</div>
</Component>
), [text, value])

children に限定しましたが 属性風に

<Component
header={<div>header</div>}
body={<div>body</div>}
/>

と書いた場合も JSX 部分で毎回異なるオブジェクトになるので 同じようにメモする必要があります



どうしても useMemo が嫌なら JSX の要素を含まない形のコンポーネントを挟むということもできます
こういうふうに useMemo を使うコンポーネントの場合

const component = useMemo(() => (
<Component value={value}>
<div>{text}</div>
</Component>
), [value, text])

return (
<div>
{component}
</div>
)

div 要素があるせいで Component のメモが複雑化します
なので JSX の要素を props で受け取らないコンポーネントを作って これを React.memo でラップします

const ComponentWrapper = ({ value, text }) => {
return (
<Component value={value}>
<div>{text}</div>
</Component>
)
}
const ComponentWrapperM = React.memo(ComponentWrapper)

このコンポーネントの props には JSX の要素は入らないので props 比較で変更されてないことを正しく検知できます
使う側はこういう感じです

return (
<div>
<ComponentWrapperM value={value} text={text} />
</div>
)