Observser Pattern を カスタムフックで実装する
最近、JavaScript(と、主にReact)のデザインパターンをまとめている ebook をちょこちょこ読み進めています。
この中で、初めて見たデザインパターンとして Observser Pattern (オブザーバパターン)というパターンが出てきたのですが、ここでの書き方が ES2015 以降のクラスを用いた書き方だったので、勉強がてら React のカスタムフックを使った実装に書き換えてみます。
元の実装で Observable.js
内で書かれていたものを、 useObserver
フックとして定義しました。
Observable.js
で、メンバ変数として定義されていた observers
を、ここではステートとして管理しています。その他はすべてシンプルな関数です。
// useObserver.js import { useState } from "react"; export const useObserver = () => { const [observers, setObservers] = useState([]); const subscribe = (f) => { setObservers(f); }; const unsubscribe = (f) => { setObservers(observers.filter((o) => o !== f)); }; const notify = (data) => { observers.forEach((observer) => observer(data)); }; return { observers, subscribe, unsubscribe, notify }; };
使う側である App.js
は以下のようになります。
// App.js import "./styles.css"; import { Button, Switch, FormControlLabel } from "@material-ui/core"; import { ToastContainer, toast } from "react-toastify"; import { useObserver } from "./useObserver.js"; import { useEffect } from "react"; export default function App() { const { subscribe, notify } = useObserver(); useEffect(() => { subscribe([toastify, logger]); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); function handleClick() { notify("User clicked button!"); } function handleToggle() { notify("User toggled switch!"); } function logger(data) { console.log(`${Date.now()} ${data}`); } function toastify(data) { toast(data, { position: toast.POSITION.BOTTOM_RIGHT, closeButton: false, autoClose: 2000 }); } return ( <div className="App"> <Button variant="contained" onClick={handleClick}> Click me! </Button> <FormControlLabel control={<Switch name="" onChange={handleToggle} />} label="Toggle me!" /> <ToastContainer /> </div> ); }