logo
/
カスタムフックからJSXを返すのはアンチパターン
2022-06-13
  • なぜ?
    • カスタムフックが毎回呼ばれるとJSXも毎回再生成されるため、別インスタンスとなってフォーカス等が破棄される
    • メモ化すればいいじゃんと思うけど、propsは割りと頻繁に更新されるのでそういうわけにもいかない
  • 2022-06-13
    • ほんとに?
    • ちゃんと仕様を把握したほうが良い
      • しっかりReact.memouseMemoを使用すれば全然問題なかった
      • おそらくより上のコンポーネントから破棄再生性がされていたんだと思う
 import { useState } from "react";
 import "./styles.css";

 const useRenderHook = (onSubmit: () => void) => {
   const [text, setText] = useState("");

   const onInput: React.FormEventHandler<HTMLInputElement> = (e) => {
     setText(e.currentTarget.value);
   };

   const onKeyDown: React.KeyboardEventHandler = (e) => {
     if (e.code === "Enter") {
       onSubmit();
     }
   };

   console.log("renderhook");

   const render = () => {
     return (
       <div>
         <input
           type="text"
           value={text}
           onInput={onInput}
           onKeyDown={onKeyDown}
         />
       </div>
     );
   };

   return { render, text };
 };

 const Wrapper: React.FC<{ changeColor: () => void }> = ({ changeColor }) => {
   const { render, text } = useRenderHook(changeColor);
   console.log("wrapper");
   return (
     <div className="App">
       {render()}
       <p>{text}</p>
     </div>
   );
 };

 export default function App() {
   const [color, setColor] = useState<"blue" | "red">("blue");

   const changeColor = () => {
     if (color === "red") setColor("blue");
     else setColor("red");
   };

   return (
     <div style={{ backgroundColor: color, height: "100vh" }}>
       <Wrapper {...{ changeColor }} />
     </div>
   );
 }