※当サイトの記事には、広告・プロモーションが含まれます。

Reactで『Warning: A component is changing an uncontrolled input to be controlled. 』というエラー

www.itmedia.co.jp

 MetaでInstagramを統括するアダム・モッセリ氏は「ThreadsはInstagram を利用しているため、現時点では統合された1つのアカウントのみだが、Threadsアカウントを個別に削除する方法を検討している」と、自身のThreadsで述べている。

Threadsアカウント削除にはInstagramごと削除する必要が 「Threadsだけ削除する方法、検討中」とMeta - ITmedia NEWS

Instagramのアカウントも一緒に削除されるのは、仕様として問題ありな気がしますかね...

Reactで『Warning: A component is changing an uncontrolled input to be controlled. 』というエラー

前回の、

ts0818.hatenablog.com

⇧ の時に出ていたエラーで、正確には、

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
    at input
    at label
    at td
    at tr
    at tbody
    at table
    at form
    at div
    at Page1 (http://localhost:5173/src/page/shipment/create/page1.tsx?t=1688801019183:22:20)
    at RenderedRoute (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=e3f7d3ae:3115:5)
    at Routes (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=e3f7d3ae:3483:5)
    at ShipmentItemsProvider (http://localhost:5173/src/page/shipment/create/context.tsx:20:3)
    at Router (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=e3f7d3ae:3430:15)
    at BrowserRouter (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=e3f7d3ae:3851:5)
    at div
    at App (http://localhost:5173/src/App.tsx?t=1688801019183:26:35)
    at Provider (http://localhost:5173/node_modules/.vite/deps/react-redux.js?v=e3f7d3ae:1450:3)
printWarning @ react-dom.development.js:86
error @ react-dom.development.js:60
updateWrapper @ react-dom.development.js:1813
updateProperties @ react-dom.development.js:10151
commitUpdate @ react-dom.development.js:11047
commitMutationEffectsOnFiber @ react-dom.development.js:24389
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24346
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24346
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24346
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24346
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24346
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24346
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24346
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24293
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24576
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24293
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24293
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24576
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24293
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24576
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24576
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24293
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24293
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24346
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24293
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24576
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24293
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24576
recursivelyTraverseMutationEffects @ react-dom.development.js:24273
commitMutationEffectsOnFiber @ react-dom.development.js:24432
commitMutationEffects @ react-dom.development.js:24243
commitRootImpl @ react-dom.development.js:26810
commitRoot @ react-dom.development.js:26682
finishConcurrentRender @ react-dom.development.js:25981
performConcurrentWorkOnRoot @ react-dom.development.js:25809
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533

って感じの警告なのだけど、

qiita.com

⇧ 上記サイト様が仰るには、Reactでcontrolled component化した<input>を扱う場合、value属性に初期値が設定されるようにしなきゃならんのだと。

Reactのルール、面倒くさいな...

【変更前】my-react-spa-app\src\page\shipment\create\page1.tsx

import React, { useContext, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { IInventoryShipmentPackingItemDto } from '../../../components/model/dto/shipment/inventory-shipment-packing-item-dto';
import { ShipmentItemsContext } from './context';

const Page1: React.FC = () => {
  const navigate = useNavigate();
  const { shipmentItems, setShipmentItems }: any = useContext(ShipmentItemsContext);

  console.log("shipmentItems");
  console.dir(shipmentItems);

  useEffect(() => {
    // 1ページ目に遷移した際に、shipmentItemsが未初期化の場合のみ初期化する
    if (shipmentItems.length === 0) {
      const initialShipmentItems: IInventoryShipmentPackingItemDto[] = Array.from(
        { length: 10 },
        (_, index) => ({
          itemNumber: index + 1,
          shipmentOrderNumber: '',
          shipmentPackingItemOrderNumber: '',
          numberOfOrders: 0,
          numberOfShipments: 0,
          inventoryShipmentPackingStoreItemDtoArr: [],
        })
      );
      console.log("initialShipmentItems");
      console.dir(initialShipmentItems);
      setShipmentItems([...initialShipmentItems]);
    }
  }, [shipmentItems, setShipmentItems]);

  const handleShipmentItemChange = (
    index: number
    , event: React.ChangeEvent<HTMLInputElement>
    ) => {
    event.preventDefault();
    const { name, value } = event.target;
    console.log("handleShipmentItemChange");
    console.dir(shipmentItems);
    setShipmentItems(shipmentItems.map((item: IInventoryShipmentPackingItemDto, itemIndex: number) => {

      let propertyName = name.split("_")[0];
      if (index === itemIndex) {
        return {
          ...item
          ,shipmentOrderNumber: propertyName === 'shipmentOrderNumber'? value: item.shipmentOrderNumber
          ,shipmentPackingItemOrderNumber: propertyName === 'shipmentPackingItemOrderNumber'? value: item.shipmentPackingItemOrderNumber
        };
      } else {
        return {
          ...item
        }
      }

    }))
  };

  const handleNext = (index: number, e: React.MouseEvent<HTMLButtonElement>) => {
    e.preventDefault();
    const clickedButtonParentRow = e.currentTarget.closest('tr');
    const hiddenInput = clickedButtonParentRow?.querySelector(
      `input[name="itemNumber_${index}"]`
    ) as HTMLInputElement;
    const hiddenInputValue = hiddenInput?.value;
    const selectedRowIndex = Number(hiddenInputValue) -1;
    navigate('/page2', { state: { shipmentItems, selectedRowIndex } });
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    // 1ページ目のフォームと2ページ目のフォームのデータをサーバーサイドに送信する処理
    // ...

    // データ送信後に1ページ目に遷移する
    navigate('/page1');
  };

  return (
    <div>
      <h2>ページ1</h2>
      <form onSubmit={handleSubmit}>
        <table>
          <thead className="content-header" style={{ tableLayout: 'fixed' }}>
            <tr>
              <th>No.</th>
              <th>出荷指示番号</th>
              <th>出荷指示梱包明細番号</th>
              <th></th>
            </tr>
          </thead>
          <tbody className="content-body">
            {/* 1ページ目のフォームを10回ループ */}
            {Array.from({ length: 10 }, (_, index) => (
              <tr key={index}>
                <td>
                  <label>
                    {index + 1}
                    <span style={{ display: 'none' }}>Item Number:</span>
                    <input
                      type="hidden"
                      id={`itemNumber_${index}`}
                      name={`itemNumber_${index}`}
                      value={shipmentItems[index]?.[`itemNumber`]}
                      readOnly
                    />
                  </label>
                </td>
                <td>
                  <label>
                    <span style={{ display: 'none' }}>Shipment Order Number:</span>
                    <input
                      type="text"
                      id={`shipmentOrderNumber_${index}`}
                      name={`shipmentOrderNumber_${index}`}
                      value={shipmentItems[index]?.[`shipmentOrderNumber`] || ''}
                      onChange={(e) => handleShipmentItemChange(index, e)}
                    />
                  </label>
                </td>
                <td>
                  <label>
                    <span style={{ display: 'none' }}>Shipment Packing Item Order Number:</span>
                    <input
                      type="text"
                      id={`shipmentPackingItemOrderNumber_${index}`}
                      name={`shipmentPackingItemOrderNumber_${index}`}
                      value={shipmentItems[index]?.[`shipmentPackingItemOrderNumber`] || ''}
                      onChange={(e) => handleShipmentItemChange(index, e)}
                    />
                  </label>
                </td>
                <td>
                  <button type="button" onClick={(e) => handleNext(index, e)}>
                    NEXT
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
        <button type="submit">Submit</button>
      </form>
    </div>
  );
};

export default Page1;
    

【変更後】my-react-spa-app\src\page\shipment\create\page1.tsx

import React, { useContext, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { IInventoryShipmentPackingItemDto } from '../../../components/model/dto/shipment/inventory-shipment-packing-item-dto';
import { ShipmentItemsContext } from './context';

const Page1: React.FC = () => {
  const navigate = useNavigate();
  const { shipmentItems, setShipmentItems }: any = useContext(ShipmentItemsContext);

  console.log("shipmentItems");
  console.dir(shipmentItems);

  useEffect(() => {
    // 1ページ目に遷移した際に、shipmentItemsが未初期化の場合のみ初期化する
    if (shipmentItems.length === 0) {
      const initialShipmentItems: IInventoryShipmentPackingItemDto[] = Array.from(
        { length: 10 },
        (_, index) => ({
          itemNumber: index + 1,
          shipmentOrderNumber: '',
          shipmentPackingItemOrderNumber: '',
          numberOfOrders: 0,
          numberOfShipments: 0,
          inventoryShipmentPackingStoreItemDtoArr: [],
        })
      );
      console.log("initialShipmentItems");
      console.dir(initialShipmentItems);
      setShipmentItems([...initialShipmentItems]);
    }
  }, [shipmentItems, setShipmentItems]);

  const handleShipmentItemChange = (
    index: number
    , event: React.ChangeEvent<HTMLInputElement>
    ) => {
    event.preventDefault();
    const { name, value } = event.target;
    console.log("handleShipmentItemChange");
    console.dir(shipmentItems);
    setShipmentItems(shipmentItems.map((item: IInventoryShipmentPackingItemDto, itemIndex: number) => {

      let propertyName = name.split("_")[0];
      if (index === itemIndex) {
        return {
          ...item
          ,shipmentOrderNumber: propertyName === 'shipmentOrderNumber'? value: item.shipmentOrderNumber
          ,shipmentPackingItemOrderNumber: propertyName === 'shipmentPackingItemOrderNumber'? value: item.shipmentPackingItemOrderNumber
        };
      } else {
        return {
          ...item
        }
      }

    }))
  };

  const handleNext = (index: number, e: React.MouseEvent<HTMLButtonElement>) => {
    e.preventDefault();
    const clickedButtonParentRow = e.currentTarget.closest('tr');
    const hiddenInput = clickedButtonParentRow?.querySelector(
      `input[name="itemNumber_${index}"]`
    ) as HTMLInputElement;
    const hiddenInputValue = hiddenInput?.value;
    const selectedRowIndex = Number(hiddenInputValue) -1;
    navigate('/page2', { state: { shipmentItems, selectedRowIndex } });
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    // 1ページ目のフォームと2ページ目のフォームのデータをサーバーサイドに送信する処理
    // ...

    // データ送信後に1ページ目に遷移する
    navigate('/page1');
  };

  return (
    <div>
      <h2>ページ1</h2>
      <form onSubmit={handleSubmit}>
        <table>
          <thead className="content-header" style={{ tableLayout: 'fixed' }}>
            <tr>
              <th>No.</th>
              <th>出荷指示番号</th>
              <th>出荷指示梱包明細番号</th>
              <th></th>
            </tr>
          </thead>
          <tbody className="content-body">
            {/* 1ページ目のフォームを10回ループ */}
            {Array.from({ length: 10 }, (_, index) => (
              <tr key={index}>
                <td>
                  <label>
                    {index + 1}
                    <span style={{ display: 'none' }}>Item Number:</span>
                    <input
                      type="hidden"
                      id={`itemNumber_${index}`}
                      name={`itemNumber_${index}`}
                      value={shipmentItems[index]?.[`itemNumber`] || ''}
                      readOnly
                    />
                  </label>
                </td>
                <td>
                  <label>
                    <span style={{ display: 'none' }}>Shipment Order Number:</span>
                    <input
                      type="text"
                      id={`shipmentOrderNumber_${index}`}
                      name={`shipmentOrderNumber_${index}`}
                      value={shipmentItems[index]?.[`shipmentOrderNumber`] || ''}
                      onChange={(e) => handleShipmentItemChange(index, e)}
                    />
                  </label>
                </td>
                <td>
                  <label>
                    <span style={{ display: 'none' }}>Shipment Packing Item Order Number:</span>
                    <input
                      type="text"
                      id={`shipmentPackingItemOrderNumber_${index}`}
                      name={`shipmentPackingItemOrderNumber_${index}`}
                      value={shipmentItems[index]?.[`shipmentPackingItemOrderNumber`] || ''}
                      onChange={(e) => handleShipmentItemChange(index, e)}
                    />
                  </label>
                </td>
                <td>
                  <button type="button" onClick={(e) => handleNext(index, e)}>
                    NEXT
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
        <button type="submit">Submit</button>
      </form>
    </div>
  );
};

export default Page1;
    

【変更前】my-react-spa-app\src\page\shipment\create\page2.tsx

import React, { useContext, useEffect, useState } from "react";
//import { render } from 'react-dom';
import { createRoot } from "react-dom/client";
import { useNavigate, useLocation } from "react-router-dom";
import { ShipmentItemsContext } from "./context";
import { IInventoryShipmentPackingItemDto } from "../../../components/model/dto/shipment/inventory-shipment-packing-item-dto";
import { IInventoryShipmentPackingStoreItemDto } from "../../../components/model/dto/shipment/inventory-shipment-packing-store-item-dto";

const Page2: React.FC = () => {
  const location = useLocation();
  const navigate = useNavigate();
  const shipmentItemsContext = useContext(ShipmentItemsContext);
  console.log("page2■ShipmentItemsContext");
  console.dir(shipmentItemsContext);

  // const [isRender, setIsRender] = useState(true);
  // const [onloaded, setOnloaded] = useState(false);
  // const [isInit, setIsInit] = useState(false);
  const [isReadyRender, setIsReadyRender] = useState(false);

  if (!shipmentItemsContext) {
    // ShipmentItemsContextが未定義の場合のエラーハンドリング
    return null;
  }

  // 選択された行の番号
  const selectedRowIndex = location.state?.selectedRowIndex || 0;
  // let stateShipmetItemArr: IInventoryShipmentPackingItemDto[] = location.state?.shipmentItems || [];

  console.log("location.state");
  console.dir(location.state);

  //let [shipmentItems, setShipmentItems] = useState<
  // const [shipmentItems, setShipmentItems] = useState<
  //   IInventoryShipmentPackingItemDto[]
  // >(
  //   location.state && location.state.shipmentItems
  //     ? location.state.shipmentItems
  //     : []
  // );
  const { shipmentItems, setShipmentItems }: any = useContext(ShipmentItemsContext);

  console.log("shipmentItemsContext");
  console.dir(shipmentItemsContext);

  // サーバーサイドからデータが取得された想定
  let initShipmentItems: any = [];
  let tableBody: JSX.Element[] = [] as JSX.Element[];

  let storeData = [
    { packingChainStoreCode: "01", storeName: "保谷店" },
    { packingChainStoreCode: "02", storeName: "大泉学園店" },
    { packingChainStoreCode: "03", storeName: "練馬駅前店" },
    { packingChainStoreCode: "04", storeName: "石神井公園店" },
    { packingChainStoreCode: "05", storeName: "石神井台店" },
    { packingChainStoreCode: "06", storeName: "練馬店" },
    { packingChainStoreCode: "07", storeName: "中村橋店" },
    { packingChainStoreCode: "08", storeName: "成増店" },
    { packingChainStoreCode: "09", storeName: "田無店" },
    { packingChainStoreCode: "10", storeName: "東中野店" },
    { packingChainStoreCode: "11", storeName: "高円寺店" },
    { packingChainStoreCode: "12", storeName: "笹塚店" },
    { packingChainStoreCode: "13", storeName: "上池袋店" },
    { packingChainStoreCode: "14", storeName: "東新宿店" },
    { packingChainStoreCode: "15", storeName: "新宿店" },
    { packingChainStoreCode: "16", storeName: "中野店" },
    { packingChainStoreCode: "17", storeName: "三鷹店" },
    { packingChainStoreCode: "18", storeName: "武蔵境店" },
    { packingChainStoreCode: "19", storeName: "吉祥寺店" },
    { packingChainStoreCode: "20", storeName: "西荻窪店" },
  ];

  React.useEffect(() => {

    const isAreadyInit: boolean = shipmentItems.every((item: IInventoryShipmentPackingItemDto) => item.inventoryShipmentPackingStoreItemDtoArr.length !== 0)
    if (isAreadyInit) {
      return;
    }

    console.log("【useEffect】【start】初回実行");
    // 選択された行の情報を取得
    // const selectedRow = location.state.shipmentItems[selectedRowIndex];
    const copyShipmentItems = JSON.parse(JSON.stringify(shipmentItems));
    console.log("copyShipmentItems");
    console.dir(copyShipmentItems);

    const initialShipmentItems: IInventoryShipmentPackingItemDto[] =
      //location.state.shipmentItems.map((item: any, itemIndex: number) => {
      copyShipmentItems.map((item: any, itemIndex: number) => {
        // 店舗別の情報(更新用)
        let inventoryShipmentPackingStoreItemDtoArr: IInventoryShipmentPackingStoreItemDto[] =
          [];
        // 店舗別発注数合計
        let totalStoreNumberOfOrders = 0;
        // 店舗別出荷数合計
        let totalStoreNumberOfShipments = 0;
        // 店舗別の情報(作業用)
        const inventoryShipmentPackingStoreItemDtoWorkArr =
          item[selectedRowIndex]?.inventoryShipmentPackingStoreItemDtoArr || [];

        // サーバーからのデータを設定していく
        storeData.forEach((store: any, storeIndex: number) => {
          // 店舗別の情報
          // const selected = inventoryShipmentPackingStoreItemDtoWorkArr.some(
          //   (storeItem: any) =>
          //     storeItem?.packingChainStoreCode === store.packingChainStoreCode
          // );

          // 選択されてる行の場合だけ実施
          if (itemIndex === selectedRowIndex) {
            // 店舗別の発注数、出荷数の合計を算出する
            item.inventoryShipmentPackingStoreItemDtoArr.forEach(
              (itemStore: any, itemStoreIndex: number) => {
                // 発注数の合計
                if (Number.isInteger(itemStore.numberOfOrders)) {
                  totalStoreNumberOfOrders += itemStore.numberOfOrders;
                }
                // 出荷数の合計
                if (Number.isInteger(itemStore.numberOfShipments)) {
                  totalStoreNumberOfShipments += itemStore.numberOfShipments;
                }
              }
            );
          }

          // 店舗別の情報(更新用)を作成する
          inventoryShipmentPackingStoreItemDtoArr.push({
            itemNumber: location.state.shipmentItems[itemIndex].itemNumber,
            shipmentOrderNumber: "",
            shipmentPackingItemOrderNumber: "",
            chainCorporateCode: "",
            packingChainStoreCode: store.packingChainStoreCode,
            storeName: store.storeName,
            numberOfOrders:
              inventoryShipmentPackingStoreItemDtoWorkArr[storeIndex]
                ?.numberOfOrders || 0,
            numberOfShipments:
              inventoryShipmentPackingStoreItemDtoWorkArr[storeIndex]
                ?.numberOfShipments || 0,
          });
        });

        // 選択されてる明細行の情報を引き続く
        let itemNumber: number =
          location.state.shipmentItems[itemIndex].itemNumber;
        let shipmentOrderNumber: string =
          itemIndex === selectedRowIndex ? item?.shipmentOrderNumber : "";
        let shipmentPackingItemOrderNumber: string =
          itemIndex === selectedRowIndex
            ? item?.shipmentPackingItemOrderNumber
            : "";

        return {
          itemNumber: itemNumber,
          shipmentOrderNumber: shipmentOrderNumber,
          shipmentPackingItemOrderNumber: shipmentPackingItemOrderNumber,
          numberOfOrders: totalStoreNumberOfOrders,
          numberOfShipments: totalStoreNumberOfShipments,
          inventoryShipmentPackingStoreItemDtoArr:
            inventoryShipmentPackingStoreItemDtoArr,
        };
      });

    console.log("initialShipmentItems");
    console.dir(initialShipmentItems);
    // shipmentItemsを更新する
    //shipmentItems = initialShipmentItems;
    setShipmentItems(
      initialShipmentItems.map((shipmentItem, index) => {
        return {
          ...shipmentItem,
          numberOfOrders: shipmentItem.numberOfOrders,
          numberOfShipments: shipmentItem.numberOfShipments,
          inventoryShipmentPackingStoreItemDtoArr:
            shipmentItem.inventoryShipmentPackingStoreItemDtoArr.map(
              (store, storeIndex) => {
                return {
                  ...store,
                  storeName: store.storeName,
                  packingChainStoreCode: store.packingChainStoreCode,
                  numberOfOrders: store.numberOfOrders,
                  numberOfShipments: store.numberOfShipments,
                };
              }
            ),
        };
      })
    );
    initShipmentItems = initialShipmentItems;
    console.log("【useEffect】【end】初回実行");
    //setIsInit(true);
  }, []);

  // shipmentItemsが更新された後に実行される処理
  React.useEffect(() => {
    console.log("【useEffect】【start】shipmentItemsの更新");
    console.log("setShipmentItems(initialShipmentItems);が実行されました。");
    console.log("shipmentItems");
    console.dir(shipmentItems);
    console.log("initShipmentItems");
    console.dir(initShipmentItems);
    // <tbody>の部分を作成する
    //tableBody = renderFormFields();
    //setIsRender(true);
    console.log("isAready");
    //console.dir(isRender);
    console.log("tableBody");
    console.dir(tableBody);
    console.dir(typeof tableBody);
    tableBody.map((element: JSX.Element) => {
      console.dir(React.isValidElement(element));
    });
    // レンダリングの準備ができた
    setIsReadyRender(true);
    // if (isInit) {
    //   console.log("tbody更新");
    //   console.log("updated");
    //   const tbody = document.getElementById("tbody");
    //   if (tbody) {
    //     const root = createRoot(tbody);
    //     root.render(renderFormFields());
        
    //   }

    // }

    console.log("【useEffect】【end】shipmentItemsの更新");
  }, [shipmentItems]);

  // <input>の値が変更されたら実施
  const handleInputChange = (
    selectedItemIndex: number,
    event: React.ChangeEvent<HTMLInputElement>
  ) => {
    event.preventDefault();
    const { name, value } = event.target;
    console.log("name");
    console.log(name);
    console.log("value");
    console.log(value);
    let propertyName = name.split("_")[0];

    const copyForUpdateShipments = JSON.parse(JSON.stringify(shipmentItems));
    const updateShipments: IInventoryShipmentPackingItemDto[] = copyForUpdateShipments.map((item: IInventoryShipmentPackingItemDto, index: number) => {
      
      // 店舗別の情報を更新
      const workIInventoryShipmentPackingStoreItemDtoArr = item.inventoryShipmentPackingStoreItemDtoArr.map((store: IInventoryShipmentPackingStoreItemDto, storeIndex: number) => {
        if (storeIndex === selectedItemIndex) {
          return {
            ...store,
            numberOfOrders: propertyName === 'numberOfOrders'? value: store.numberOfOrders,
            numberOfShipments: propertyName === 'numberOfShipments'? value: store.numberOfShipments
          }
        } else {
          return {
            ...store
          }
        }
      });

      return {
        ...item,
        inventoryShipmentPackingStoreItemDtoArr: workIInventoryShipmentPackingStoreItemDtoArr
      }

    });

    setShipmentItems(updateShipments);

    // shipmentItems = updatedShipmentItems;
    //renderFormFields();
  };

  console.log("handleInputChange■shipmentItems");
  console.dir(shipmentItems);
  console.dir(shipmentItems[selectedRowIndex]);

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    // フォームの送信処理
  };

  // <tbody>部分を作成する処理
  const renderFormFields = () => {
    const formFields: JSX.Element[] = [];
    console.log("renderFormFields■shipmentItems");
    console.dir(shipmentItems[selectedRowIndex]);

    {
      /* 店舗の数だけ繰り返し */
    }
    for (let i = 0; i < storeData.length; i += 4) {
      const rowFields: JSX.Element[] = [];

      {
        /* 1行に4店舗 */
      }
      for (let j = i; j < i + 4; j++) {
        if (j >= storeData.length) {
          break;
        }

        let itemIndex = j;
        rowFields.push(
          <td>
            <div style={{ display: "flex" }}>
              <div style={{ minWidth: "128px" }}>
                {/* 梱包対象チェーン店舗コード */}
                <div>
                  <span>
                    {
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `packingChainStoreCode`
                      ]
                    }
                  </span>
                  <input
                    style={{ width: "100%", boxSizing: "border-box" }}
                    type="hidden"
                    id={`packingChainStoreCode_${itemIndex}`}
                    key={`packingChainStoreCode_${itemIndex}`}
                    name={`packingChainStoreCode_${itemIndex}`}
                    value={
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `packingChainStoreCode`
                      ]
                    }
                  />
                </div>
                {/* 店舗名 */}
                <div>
                  <span>
                    {
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `storeName`
                      ]
                    }
                  </span>
                  <input
                    style={{ width: "100%", boxSizing: "border-box" }}
                    type="hidden"
                    id={`storeName_${itemIndex}`}
                    key={`storeName_${itemIndex}`}
                    name={`storeName_${itemIndex}`}
                    value={
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `storeName`
                      ]
                    }
                  />
                </div>
              </div>
              <div>
                {/* 店舗別発注数 */}
                <div>
                  <input
                    style={{ width: "100%", boxSizing: "border-box" }}
                    type="text"
                    id={`numberOfOrders_${itemIndex}`}
                    key={`numberOfOrders_${itemIndex}`}
                    name={`numberOfOrders_${itemIndex}`}
                    value={
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `numberOfOrders` || ''
                      ]
                    }
                    onChange={(e) => handleInputChange(itemIndex, e)}
                  />
                </div>
                {/* 店舗別出荷数 */}
                <div>
                  <input
                    style={{ width: "100%", boxSizing: "border-box" }}
                    type="text"
                    id={`numberOfShipments_${itemIndex}`}
                    key={`numberOfShipments_${itemIndex}`}
                    name={`numberOfShipments_${itemIndex}`}
                    value={
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `numberOfShipments` || ''
                      ]
                    }
                    onChange={(e) => handleInputChange(itemIndex, e)}
                  />
                </div>
              </div>
            </div>
          </td>
        );
      }
      formFields.push(<tr key={i}>{rowFields}</tr>);
    }

    return formFields;
  };

  // <thead>部分を作成する処理
  const renderTableHeaders = () => {
    const headers: JSX.Element[] = [];
    const cells: JSX.Element[] = [];
    for (let i = 0; i < 4; i++) {
      cells.push(
        <th key={i}>
          {/* 適切なヘッダーテキストを表示 */}
          <div style={{ display: "flex" }}>
            <div style={{ minWidth: "128px" }}>
              <span>店舗コード</span>
              <br />
              <span>店舗名</span>
            </div>
            <div style={{ minWidth: "128px" }}>
                <span>店舗別発注数</span>
              <br />
              <span>店舗別出荷数</span>
            </div>
          </div>
        </th>
      );
    }

    headers.push(<tr key={0}>{cells}</tr>);

    return headers;
  };

  // const onPageLoaded = () => {
  //   setOnloaded(true);
  // };

  // if (document.readyState === "complete") {
  //   if (!onloaded) {
  //     () => onPageLoaded();
  //   }
  // } else {
  //   window.addEventListener("load", onPageLoaded);
  //   window.removeEventListener("load", onPageLoaded);
  // }

  // // 初期化が済んでいれば実施
  // useEffect(() => {
  //   const tbody = document.getElementById("tbody");
  //   console.log("tbody");
  //   console.dir(tbody);
  //   if (tbody && tbody.childNodes.length === 0) {
  //     console.log("dom loaded");
  //     console.log("レンダリング時:shipmentItems");
  //     console.dir(shipmentItems);
  //     const root = createRoot(tbody);
  //     root.render(tableBody);
  //     // tableBody.map((element) => {
  //     //   root.render(element);
  //     // });
  //     //setOnloaded(false);
  //   }
  // }, [isInit]);

  // 画面の描画
  return (
    <div>
      {/* {isRender ? (*/}
      {isReadyRender ? (
        <>
          <h2>Page 2</h2>
          <form onSubmit={handleSubmit}>
            <table>
              <thead>{renderTableHeaders()}</thead>
              <tbody id="tbody">{renderFormFields()}</tbody>
            </table>
            <div>
              <button type="submit">次へ</button>
              <button type="button" onClick={() => navigate(-1)}>
                戻る
              </button>
            </div>
          </form>
        </>
      ) : (
        <>
          <p>...loading</p>
        </>
      )}
    </div>
  );
};

export default Page2;

【変更後】my-react-spa-app\src\page\shipment\create\page2.tsx

import React, { useContext, useEffect, useState } from "react";
//import { render } from 'react-dom';
import { createRoot } from "react-dom/client";
import { useNavigate, useLocation } from "react-router-dom";
import { ShipmentItemsContext } from "./context";
import { IInventoryShipmentPackingItemDto } from "../../../components/model/dto/shipment/inventory-shipment-packing-item-dto";
import { IInventoryShipmentPackingStoreItemDto } from "../../../components/model/dto/shipment/inventory-shipment-packing-store-item-dto";

const Page2: React.FC = () => {
  const location = useLocation();
  const navigate = useNavigate();
  const shipmentItemsContext = useContext(ShipmentItemsContext);
  console.log("page2■ShipmentItemsContext");
  console.dir(shipmentItemsContext);

  // const [isRender, setIsRender] = useState(true);
  // const [onloaded, setOnloaded] = useState(false);
  // const [isInit, setIsInit] = useState(false);
  const [isReadyRender, setIsReadyRender] = useState(false);

  if (!shipmentItemsContext) {
    // ShipmentItemsContextが未定義の場合のエラーハンドリング
    return null;
  }

  // 選択された行の番号
  const selectedRowIndex = location.state?.selectedRowIndex || 0;
  // let stateShipmetItemArr: IInventoryShipmentPackingItemDto[] = location.state?.shipmentItems || [];

  console.log("location.state");
  console.dir(location.state);

  //let [shipmentItems, setShipmentItems] = useState<
  // const [shipmentItems, setShipmentItems] = useState<
  //   IInventoryShipmentPackingItemDto[]
  // >(
  //   location.state && location.state.shipmentItems
  //     ? location.state.shipmentItems
  //     : []
  // );
  const { shipmentItems, setShipmentItems }: any = useContext(ShipmentItemsContext);

  console.log("shipmentItemsContext");
  console.dir(shipmentItemsContext);

  // サーバーサイドからデータが取得された想定
  let initShipmentItems: any = [];
  let tableBody: JSX.Element[] = [] as JSX.Element[];

  let storeData = [
    { packingChainStoreCode: "01", storeName: "保谷店" },
    { packingChainStoreCode: "02", storeName: "大泉学園店" },
    { packingChainStoreCode: "03", storeName: "練馬駅前店" },
    { packingChainStoreCode: "04", storeName: "石神井公園店" },
    { packingChainStoreCode: "05", storeName: "石神井台店" },
    { packingChainStoreCode: "06", storeName: "練馬店" },
    { packingChainStoreCode: "07", storeName: "中村橋店" },
    { packingChainStoreCode: "08", storeName: "成増店" },
    { packingChainStoreCode: "09", storeName: "田無店" },
    { packingChainStoreCode: "10", storeName: "東中野店" },
    { packingChainStoreCode: "11", storeName: "高円寺店" },
    { packingChainStoreCode: "12", storeName: "笹塚店" },
    { packingChainStoreCode: "13", storeName: "上池袋店" },
    { packingChainStoreCode: "14", storeName: "東新宿店" },
    { packingChainStoreCode: "15", storeName: "新宿店" },
    { packingChainStoreCode: "16", storeName: "中野店" },
    { packingChainStoreCode: "17", storeName: "三鷹店" },
    { packingChainStoreCode: "18", storeName: "武蔵境店" },
    { packingChainStoreCode: "19", storeName: "吉祥寺店" },
    { packingChainStoreCode: "20", storeName: "西荻窪店" },
  ];

  React.useEffect(() => {

    const isAreadyInit: boolean = shipmentItems.every((item: IInventoryShipmentPackingItemDto) => item.inventoryShipmentPackingStoreItemDtoArr.length !== 0)
    if (isAreadyInit) {
      return;
    }

    console.log("【useEffect】【start】初回実行");
    // 選択された行の情報を取得
    // const selectedRow = location.state.shipmentItems[selectedRowIndex];
    const copyShipmentItems = JSON.parse(JSON.stringify(shipmentItems));
    console.log("copyShipmentItems");
    console.dir(copyShipmentItems);

    const initialShipmentItems: IInventoryShipmentPackingItemDto[] =
      //location.state.shipmentItems.map((item: any, itemIndex: number) => {
      copyShipmentItems.map((item: any, itemIndex: number) => {
        // 店舗別の情報(更新用)
        let inventoryShipmentPackingStoreItemDtoArr: IInventoryShipmentPackingStoreItemDto[] =
          [];
        // 店舗別発注数合計
        let totalStoreNumberOfOrders = 0;
        // 店舗別出荷数合計
        let totalStoreNumberOfShipments = 0;
        // 店舗別の情報(作業用)
        const inventoryShipmentPackingStoreItemDtoWorkArr =
          item[selectedRowIndex]?.inventoryShipmentPackingStoreItemDtoArr || [];

        // サーバーからのデータを設定していく
        storeData.forEach((store: any, storeIndex: number) => {
          // 店舗別の情報
          // const selected = inventoryShipmentPackingStoreItemDtoWorkArr.some(
          //   (storeItem: any) =>
          //     storeItem?.packingChainStoreCode === store.packingChainStoreCode
          // );

          // 選択されてる行の場合だけ実施
          if (itemIndex === selectedRowIndex) {
            // 店舗別の発注数、出荷数の合計を算出する
            item.inventoryShipmentPackingStoreItemDtoArr.forEach(
              (itemStore: any, itemStoreIndex: number) => {
                // 発注数の合計
                if (Number.isInteger(itemStore.numberOfOrders)) {
                  totalStoreNumberOfOrders += itemStore.numberOfOrders;
                }
                // 出荷数の合計
                if (Number.isInteger(itemStore.numberOfShipments)) {
                  totalStoreNumberOfShipments += itemStore.numberOfShipments;
                }
              }
            );
          }

          // 店舗別の情報(更新用)を作成する
          inventoryShipmentPackingStoreItemDtoArr.push({
            itemNumber: location.state.shipmentItems[itemIndex].itemNumber,
            shipmentOrderNumber: "",
            shipmentPackingItemOrderNumber: "",
            chainCorporateCode: "",
            packingChainStoreCode: store.packingChainStoreCode,
            storeName: store.storeName,
            numberOfOrders:
              inventoryShipmentPackingStoreItemDtoWorkArr[storeIndex]
                ?.numberOfOrders || 0,
            numberOfShipments:
              inventoryShipmentPackingStoreItemDtoWorkArr[storeIndex]
                ?.numberOfShipments || 0,
          });
        });

        // 選択されてる明細行の情報を引き続く
        let itemNumber: number =
          location.state.shipmentItems[itemIndex].itemNumber;
        let shipmentOrderNumber: string =
          itemIndex === selectedRowIndex ? item?.shipmentOrderNumber : "";
        let shipmentPackingItemOrderNumber: string =
          itemIndex === selectedRowIndex
            ? item?.shipmentPackingItemOrderNumber
            : "";

        return {
          itemNumber: itemNumber,
          shipmentOrderNumber: shipmentOrderNumber,
          shipmentPackingItemOrderNumber: shipmentPackingItemOrderNumber,
          numberOfOrders: totalStoreNumberOfOrders,
          numberOfShipments: totalStoreNumberOfShipments,
          inventoryShipmentPackingStoreItemDtoArr:
            inventoryShipmentPackingStoreItemDtoArr,
        };
      });

    console.log("initialShipmentItems");
    console.dir(initialShipmentItems);
    // shipmentItemsを更新する
    //shipmentItems = initialShipmentItems;
    setShipmentItems(
      initialShipmentItems.map((shipmentItem, index) => {
        return {
          ...shipmentItem,
          numberOfOrders: shipmentItem.numberOfOrders,
          numberOfShipments: shipmentItem.numberOfShipments,
          inventoryShipmentPackingStoreItemDtoArr:
            shipmentItem.inventoryShipmentPackingStoreItemDtoArr.map(
              (store, storeIndex) => {
                return {
                  ...store,
                  storeName: store.storeName,
                  packingChainStoreCode: store.packingChainStoreCode,
                  numberOfOrders: store.numberOfOrders,
                  numberOfShipments: store.numberOfShipments,
                };
              }
            ),
        };
      })
    );
    initShipmentItems = initialShipmentItems;
    console.log("【useEffect】【end】初回実行");
    //setIsInit(true);
  }, []);

  // shipmentItemsが更新された後に実行される処理
  React.useEffect(() => {
    console.log("【useEffect】【start】shipmentItemsの更新");
    console.log("setShipmentItems(initialShipmentItems);が実行されました。");
    console.log("shipmentItems");
    console.dir(shipmentItems);
    console.log("initShipmentItems");
    console.dir(initShipmentItems);
    // <tbody>の部分を作成する
    //tableBody = renderFormFields();
    //setIsRender(true);
    console.log("isAready");
    //console.dir(isRender);
    console.log("tableBody");
    console.dir(tableBody);
    console.dir(typeof tableBody);
    tableBody.map((element: JSX.Element) => {
      console.dir(React.isValidElement(element));
    });
    // レンダリングの準備ができた
    setIsReadyRender(true);
    // if (isInit) {
    //   console.log("tbody更新");
    //   console.log("updated");
    //   const tbody = document.getElementById("tbody");
    //   if (tbody) {
    //     const root = createRoot(tbody);
    //     root.render(renderFormFields());
        
    //   }

    // }

    console.log("【useEffect】【end】shipmentItemsの更新");
  }, [shipmentItems]);

  // <input>の値が変更されたら実施
  const handleInputChange = (
    selectedItemIndex: number,
    event: React.ChangeEvent<HTMLInputElement>
  ) => {
    event.preventDefault();
    const { name, value } = event.target;
    console.log("name");
    console.log(name);
    console.log("value");
    console.log(value);
    let propertyName = name.split("_")[0];

    const copyForUpdateShipments = JSON.parse(JSON.stringify(shipmentItems));
    const updateShipments: IInventoryShipmentPackingItemDto[] = copyForUpdateShipments.map((item: IInventoryShipmentPackingItemDto, index: number) => {
      
      // 店舗別の情報を更新
      const workIInventoryShipmentPackingStoreItemDtoArr = item.inventoryShipmentPackingStoreItemDtoArr.map((store: IInventoryShipmentPackingStoreItemDto, storeIndex: number) => {
        if (storeIndex === selectedItemIndex) {
          return {
            ...store,
            numberOfOrders: propertyName === 'numberOfOrders'? value: store.numberOfOrders,
            numberOfShipments: propertyName === 'numberOfShipments'? value: store.numberOfShipments
          }
        } else {
          return {
            ...store
          }
        }
      });

      return {
        ...item,
        inventoryShipmentPackingStoreItemDtoArr: workIInventoryShipmentPackingStoreItemDtoArr
      }

    });

    setShipmentItems(updateShipments);

    // shipmentItems = updatedShipmentItems;
    //renderFormFields();
  };

  console.log("handleInputChange■shipmentItems");
  console.dir(shipmentItems);
  console.dir(shipmentItems[selectedRowIndex]);

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    // フォームの送信処理
  };

  // <tbody>部分を作成する処理
  const renderFormFields = () => {
    const formFields: JSX.Element[] = [];
    console.log("renderFormFields■shipmentItems");
    console.dir(shipmentItems[selectedRowIndex]);

    {
      /* 店舗の数だけ繰り返し */
    }
    for (let i = 0; i < storeData.length; i += 4) {
      const rowFields: JSX.Element[] = [];

      {
        /* 1行に4店舗 */
      }
      for (let j = i; j < i + 4; j++) {
        if (j >= storeData.length) {
          break;
        }

        let itemIndex = j;
        rowFields.push(
          <td>
            <div style={{ display: "flex" }}>
              <div style={{ minWidth: "128px" }}>
                {/* 梱包対象チェーン店舗コード */}
                <div>
                  <span>
                    {
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `packingChainStoreCode`
                      ]
                    }
                  </span>
                  <input
                    style={{ width: "100%", boxSizing: "border-box" }}
                    type="hidden"
                    id={`packingChainStoreCode_${itemIndex}`}
                    key={`packingChainStoreCode_${itemIndex}`}
                    name={`packingChainStoreCode_${itemIndex}`}
                    value={
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `packingChainStoreCode` || ''
                      ]
                    }
                  />
                </div>
                {/* 店舗名 */}
                <div>
                  <span>
                    {
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `storeName`
                      ]
                    }
                  </span>
                  <input
                    style={{ width: "100%", boxSizing: "border-box" }}
                    type="hidden"
                    id={`storeName_${itemIndex}`}
                    key={`storeName_${itemIndex}`}
                    name={`storeName_${itemIndex}`}
                    value={
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `storeName` || ''
                      ]
                    }
                  />
                </div>
              </div>
              <div>
                {/* 店舗別発注数 */}
                <div>
                  <input
                    style={{ width: "100%", boxSizing: "border-box" }}
                    type="text"
                    id={`numberOfOrders_${itemIndex}`}
                    key={`numberOfOrders_${itemIndex}`}
                    name={`numberOfOrders_${itemIndex}`}
                    value={
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `numberOfOrders` || ''
                      ]
                    }
                    onChange={(e) => handleInputChange(itemIndex, e)}
                  />
                </div>
                {/* 店舗別出荷数 */}
                <div>
                  <input
                    style={{ width: "100%", boxSizing: "border-box" }}
                    type="text"
                    id={`numberOfShipments_${itemIndex}`}
                    key={`numberOfShipments_${itemIndex}`}
                    name={`numberOfShipments_${itemIndex}`}
                    value={
                      shipmentItems[selectedRowIndex]
                        ?.inventoryShipmentPackingStoreItemDtoArr[itemIndex]?.[
                        `numberOfShipments` || ''
                      ]
                    }
                    onChange={(e) => handleInputChange(itemIndex, e)}
                  />
                </div>
              </div>
            </div>
          </td>
        );
      }
      formFields.push(<tr key={i}>{rowFields}</tr>);
    }

    return formFields;
  };

  // <thead>部分を作成する処理
  const renderTableHeaders = () => {
    const headers: JSX.Element[] = [];
    const cells: JSX.Element[] = [];
    for (let i = 0; i < 4; i++) {
      cells.push(
        <th key={i}>
          {/* 適切なヘッダーテキストを表示 */}
          <div style={{ display: "flex" }}>
            <div style={{ minWidth: "128px" }}>
              <span>店舗コード</span>
              <br />
              <span>店舗名</span>
            </div>
            <div style={{ minWidth: "128px" }}>
                <span>店舗別発注数</span>
              <br />
              <span>店舗別出荷数</span>
            </div>
          </div>
        </th>
      );
    }

    headers.push(<tr key={0}>{cells}</tr>);

    return headers;
  };

  // const onPageLoaded = () => {
  //   setOnloaded(true);
  // };

  // if (document.readyState === "complete") {
  //   if (!onloaded) {
  //     () => onPageLoaded();
  //   }
  // } else {
  //   window.addEventListener("load", onPageLoaded);
  //   window.removeEventListener("load", onPageLoaded);
  // }

  // // 初期化が済んでいれば実施
  // useEffect(() => {
  //   const tbody = document.getElementById("tbody");
  //   console.log("tbody");
  //   console.dir(tbody);
  //   if (tbody && tbody.childNodes.length === 0) {
  //     console.log("dom loaded");
  //     console.log("レンダリング時:shipmentItems");
  //     console.dir(shipmentItems);
  //     const root = createRoot(tbody);
  //     root.render(tableBody);
  //     // tableBody.map((element) => {
  //     //   root.render(element);
  //     // });
  //     //setOnloaded(false);
  //   }
  // }, [isInit]);

  // 画面の描画
  return (
    <div>
      {/* {isRender ? (*/}
      {isReadyRender ? (
        <>
          <h2>Page 2</h2>
          <form onSubmit={handleSubmit}>
            <table>
              <thead>{renderTableHeaders()}</thead>
              <tbody id="tbody">{renderFormFields()}</tbody>
            </table>
            <div>
              <button type="submit">次へ</button>
              <button type="button" onClick={() => navigate(-1)}>
                戻る
              </button>
            </div>
          </form>
        </>
      ) : (
        <>
          <p>...loading</p>
        </>
      )}
    </div>
  );
};

export default Page2;

⇧ と、<input>のvalue属性にundefinedが設定されないようにしたところ、

警告が消えました。

React、独自のルールが多過ぎて、辛い...

毎度モヤモヤ感が半端ない...

今回はこのへんで。