📓

[React]ReactでVue.jsの$emitのような動きをさせたい。

2024/02/15に公開

元Vue.js使いなので$emitのようなものを実現したかったです。

どんなものを作るか

こんなのを作ります。

今、映っているボタンを子コンポーネントとして持っている親コンポーネントがconsole.log(...)を表示する処理を持っており、子コンポーネントのボタンを押すことで親コンポーネントの処理が実行されるようにします。

コード例

※今作成している匿名掲示板のコードから一部を抜粋したものを公開するので省略している部分があります。

親コンポーネント
"use client";
import RightBottomPencilButton01 from "@/components/layouts/RightBottom-PencilButton01";

export default function ButtonList() {
  const pencilButtonList = [
    {
      name: "スレの新規作成",
      action: () => {
        console.log("わーお"); //処理内容
      },
    },
    {
      name: "スレの削除",
      action: () => {
        console.log("ええやん"); //処理内容
      },
    },
  ];
  return <RightBottomPencilButton01 ButtonSet={pencilButtonList} />;
}
RightBottomPencilButton01(子コンポーネント)
export default function RightBottomPencilButton01(props: {
  ButtonSet: { name: string; action: Function }[];
}) {
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  return (
    <>
      <div className="fixed bottom-12 right-12 flex flex-col-reverse items-end gap-4">
	// 省略...
        {(() => {
          return props.ButtonSet.map((el) => {
            return (
              <MenuItem
                isMenuOpen={isMenuOpen}
                buttonName={el.name}
                //OnClickActionはボタンが押された時に実行される独自のトリガー名
                OnClickAction={() => {
                  //子コンポーネント上で親コンポーネントから渡されたFunctionを実行する
                  el.action(); 
                }}
              />
            );
          });
        })()}
      </div>
    </>
  );
}
MenuItem
function MenuItem(props: {
  buttonName: string;
  isMenuOpen: boolean;
  OnClickAction: any;
}) {
// ...
  return (
    <Transition
	// ...
    >
      <div ref={node} className="group relative flex h-14 items-center">
        <button
          onClick={props.OnClickAction} //ここでクリックされた時に実行するトリガー名を定義する。
          className="mx-auto p-3 font-Kiwi-Maru text-lg text-white opacity-0"
        >
          {props.buttonName}
        </button>
        <div className="absolute right-0 z-[-1] size-full w-0 rounded-lg border-2 bg-buttonColor01 opacity-0 transition-colors group-hover:bg-buttonHoverColor01"></div>
      </div>
    </Transition>
  );
}

解説

上記のコードは、子コンポーネント内のボタンコンポーネントのクリックによって親コンポーネントで定義した関数を実行する方法を示しています。

ButtonListコンポーネントでは、RightBottomPencilButton01コンポーネントに渡すためのボタンのリスト(pencilButtonList)を定義しています。各ボタンには、nameactionというプロパティがあります。nameはボタンの表示名を、actionはボタンがクリックされたときに実行される関数を指定しています。

RightBottomPencilButton01コンポーネントでは、渡されたボタンのリストをループして表示しています。各ボタンはMenuItemコンポーネントで表示されます。MenuItemコンポーネントはボタンの表示名とクリック時の動作を受け取り、それに基づいて表示と動作を行います。

具体的には、MenuItemコンポーネントのボタンがクリックされると、渡されたOnClickAction関数が実行されます。この関数は、親コンポーネントで定義した関数(action)を実行するためのものです。親コンポーネントで定義した関数は、ボタンがクリックされたときに実行したい処理を記述します。

このようにして、子コンポーネント内のボタンコンポーネントのクリックによって親コンポーネントで定義した関数を実行することができます。

(ちなみに解説の部分の文章はNotionのAIに作ってもらいました...スゴイネ)

やっぱReact便利だな~

Vue.jsだと$emitの使い方を覚えないといけなかったり、子コンポーネント上で親コンポーネントから受け取ったpropsの変更をすることが出来なかったりしてたので、Reactすげーって思いました。

Discussion