React: 公式ドキュメント「カスタムフックでロジックを再利用する」のサンプルの動きがおかしい

React公式ドキュメント「[カスタムフックでロジックを再利用する](https://ja.react.dev/learn/reusing-logic-with-custom-hooks)」のコードサンプルの動きがどう見てもおかしいので直しました。具体的には、「[フック間でリアクティブな値を渡す](https://ja.react.dev/learn/reusing-logic-with-custom-hooks#passing-reactive-values-between-hooks)」の[CodeSandboxのコード](https://ja.react.dev/learn/reusing-logic-with-custom-hooks#passing-reactive-values-between-hooks:~:text=Reset-,Fork,-1)です。画面には3秒おきに通知が表示されます。ドキュメント本文の解説とどう関わるのかが、まったくわかりません。


# 通知は`setInterval()`で表示されていた
通知はサーバーとの接続をシミュレートするモジュール(`chat.js`)に、`setInterval()`で表示されていました。カスタムフックの話に絡みそうにありません。クリーンアップの`clearInterval()`の呼び出しも含めて、さっくり除きましょう。

```react:chat.js
export function createConnection({ serverUrl, roomId }) {

	// let intervalId;
	let messageCallback;
	return {
		connect() {
			console.log(
				'✅ Connecting to "' + roomId + '" room at ' + serverUrl + "..."
			);
			/* clearInterval(intervalId);
			intervalId = setInterval(() => {

			}, 3000); */
		},
		disconnect() {
			// clearInterval(intervalId);
			messageCallback = null;
			console.log(
				'❌ Disconnected from "' + roomId + '" room at ' + serverUrl + ""
			);
		},

	};
}
```

こうしたら、ドキュメントの解説もわかるようになりました(サンプル001)。画面に通知は表示されず、コンソールの出力で動きが確かめられます。画面のURLやチャットルームの選択を変更すると、チャットが再接続されるというサンプルです。

**サンプル001■React: Passing reactive values between Hooks 01**
https://codesandbox.io/s/react-passing-reactive-values-between-hooks-01-vw26qp


# 接続情報を通知で示す
公式ドキュメントの解説を読むにはこれで十分です。けれど、せっかく通知を表示するライブラリ[Toastify JS](https://apvarun.github.io/toastify-js/)がインストールされているのに、使わないのももったいないように思います。そこで、コンソール出力と同じ情報(`connectionInfo`)を通知としても示すようにしてみました(サンプル002)。

```react:chat.js
export function createConnection({ serverUrl, roomId }) {

	return {
		connect() {
			const connectionInfo = `✅ Connecting to "${roomId}" room at ${serverUrl}...`;
			console.log(
				// '✅ Connecting to "' + roomId + '" room at ' + serverUrl + "..."
				connectionInfo
			);
			messageCallback && messageCallback(connectionInfo, 'white');
		},
		disconnect() {
			const connectionInfo = `❌ Disconnected from "${roomId}" room at ${serverUrl}`;
			// messageCallback = null;
			console.log(
				// '❌ Disconnected from "' + roomId + '" room at ' + serverUrl + ""
				connectionInfo
			);
			messageCallback && messageCallback(connectionInfo, 'dark');
			messageCallback = null;
		},

	};
}
```

```react:ChatRoom.js
export default function ChatRoom({ roomId }) {

	useEffect(() => {

		// connection.on("message", (msg) => {
		connection.on("message", (msg, theme) => {
			// showNotification('New message: ' + msg);
			showNotification("New connection: " + msg, theme);
		});

	}, [roomId, serverUrl]);

}
```

**サンプル002■React: Passing reactive values between Hooks 02**
https://codesandbox.io/s/react-passing-reactive-values-between-hooks-02-mcp2ty


# エフェクトのコードをカスタムフックに切り出す
もうひとつ、公式ドキュメントの主題であるカスタムフックへのロジックの切り出しまでやってしまいましょう。

コンポーネント`ChatRoom`のエフェクトを、そのまま新たなカスタムフック`useChatRoom`に移します。引数オブジェクトからは、`serverUrl`と`roomId`を受け取ることにしました。

```react:useChatRoom.js
import { useEffect } from 'react';
import { createConnection } from './chat.js';
import { showNotification } from './notifications.js';

export const useChatRoom = ({ serverUrl, roomId }) => {
	useEffect(() => {
		const options = { serverUrl, roomId };
		const connection = createConnection(options);
		connection.on('message', (msg, theme) => {
			showNotification('New connection: ' + msg, theme);
		});
		connection.connect();
		return () => connection.disconnect();
	}, [roomId, serverUrl]);
};
```
`ChatRoom`コンポーネントに、もうエフェクトは要りません。カスタムフック`useChatRoom`の引数オブジェクトに、`serverUrl`と`roomId`を渡して呼び出せば済むからです(サンプル003)。ロジックが切り分けられて、コードは読みやすくなったでしょう。

```react:ChatRoom.js
// import { useState, useEffect } from "react";
import { useState } from "react";
import { useChatRoom } from "./useChatRoom.js";
// import { createConnection } from "./chat.js";
// import { showNotification } from "./notifications.js";

export default function ChatRoom({ roomId }) {

	/* useEffect(() => {

	}, [roomId, serverUrl]); */
	useChatRoom({ serverUrl, roomId });

}
```

**サンプル003■React: Passing reactive values between Hooks 03**
https://codesandbox.io/s/react-passing-reactive-values-between-hooks-03-4dpslt


# TypeScriptを採り入れる
ご参考までに、TypeScriptを採り入れて型づけしたのがサンプル004です。少しコードも整理しました。

**サンプル004■React: Passing reactive values between Hooks 04**
https://codesandbox.io/s/react-passing-reactive-values-between-hooks-04-vmx36j

公式サンプルに、なぜあのような余分なコードが含まれていたのかは謎です。はじめにつくった作例が改定されたにしては、カスタムフックの主題には、絡むどころかかすりもしそうにありません。ブラウザでひと目見たら気づきそうなものです。おそらく、忙しかったのでしょう。