動的にコンポーネントを切り替える方法

コンポーネントのオブジェクトの状態によって子コンポーネントを動的に切り替える。かつ、親コンポーネントのマウスイベントから子コンポーネントのメソッドを呼び出す。

useRecoil を使うのがミソか。

import {
  useEffect,
  useState,
  forwardRef,
  useRef,
  useImperativeHandle,
  Children,
} from "react";
import { useRecoilState } from "recoil";
import { flagState, positionState } from "./state.jsx";

const Klass1 = forwardRef((props, ref) => {
  const [position, setPosition] = useRecoilState(positionState);

  useImperativeHandle(ref, () => ({
    updatePosition,
  }));

  const updatePosition = (event) => {
    setPosition({
      x: event.clientX,
      y: event.clientY,
    });
  };

  return <>{props.children}</>;
});

const Klass2 = forwardRef((props, ref) => {
  const [position, setPosition] = useRecoilState(positionState);

  useImperativeHandle(ref, () => ({
    updatePosition,
  }));

  const updatePosition = (event) => {
    setPosition((prev) => {
      return {
        x: prev.x + 1,
        y: prev.y + 1,
      };
    });
  };

  return <>{props.children}</>;
});

const Factory = ({ flag, children, childRef }) => {
  if (flag) {
    return <Klass1 ref={childRef}>{children}</Klass1>;
  } else {
    return <Klass2 ref={childRef}>{children}</Klass2>;
  }
};

const MyComponents = () => {
  const [flag, setFlag] = useRecoilState(flagState);
  const [position, setPostion] = useRecoilState(positionState);

  const childRef = useRef();

  const style = {
    width: 120,
    height: 120,
    backgroundColor: "green",
  };

  return (
    <Factory flag={flag} childRef={childRef}>
      <div
        id="my_components"
        style={style}
        onMouseMove={(event) => childRef.current.updatePosition(event)}
      >
        <label>
          x={position.x}, y={position.y}
        </label>
      </div>
    </Factory>
  );
};

export default MyComponents;