首页 > 解决方案 > 使用 React.useMemo 将数组传递给 react-table,由于渲染,其中一个 useMemo 返回一个空数组

问题描述

我为我的数据使用了两个不同的 api,并使用 React 备忘录将它们作为变量传递给 react-table useTable 函数。当我在没有 useTable 的情况下运行所有​​代码时,reactMemo 似乎可以工作,我可以控制我传递给使用表的两个变量,headerColumns & colArrayData但是当我使用 useTable 时,headerColumns 变量是一个空数组,破坏了 useTable。

我认为这一定是因为一些重新渲染或副作用的反应导致数组在使用表时为空。我该如何解决这个问题。

这是有问题的代码




const fetchWithId = (url, id) => fetch(`${url}?id=${id}`).then((r) => r.json());


const fetcher = (url) => fetch(url).then((r) => r.json());

export default function FormData() {

  const { data: cookieData, error: cookieError } = useSWR(
    "/api/cookie",
    fetcher
  );
  const Router = useRouter();
  const { data, error } = useSWR([`/api/data`, Router.query.id], fetchWithId);

  var test = `Bearer ${cookieData}`;

  const { loading, error: inputError, data: inputNames } = useQuery(
    INPUT_VALUES,
    {
      variables: { id: Router.query.id },
      context: {
        headers: {
          authorization: test,
        },
      },
      skip: !test,
    }
  );

  const [inputDataState, setInputDataState] = useState([]);

  useEffect(() => {
    const inputData = inputNames?.findFormByID?.formInputVals?.data;
    let arr = [...inputData, { name: "Sheet Add" }];
    console.log(arr);
    setInputDataState(arr);
  }, [inputNames]);


  const header = inputDataState?.map((item, i) => {
    console.log(item);
    return { Header: item.name, accessor: `col${i}` };
  });
  console.log(header);

  const headerColumns = React.useMemo(() => header, [inputNames]); // THIS ONE DOES NOT SEEM TO WORK


  
  const well = data?.data.map((item, i) => {
    delete item.data["FormID"];
    delete item.data["user"];
    delete item.data["visible"];
    delete item.data["sheetName"];
    item.data["refId"] = item.ref["@ref"].id;
    const ok = Object.values(item.data);
    const ref = item.ref["@ref"].id;

    return ok.map((value, i) => {
      return { [`col${i}`]: value };
    });
  });

  const result = well?.map((a) => Object.assign({}, ...a));

  console.log(result);

  const colArrayData = React.useMemo(() => result, [data]); // THIS ONE SEEMS TO WORK

  console.log("data");


  console.log(headerColumns); // RETURNS AN EMPTY ARRAY WHEN useTable is set

  console.log(colArrayData);

  const tableInstance = useTable({ headerColumns, colArrayData }); //CAUSES CANNOT READ PROPERTY OF UNDEFINED



  if (!data || loading) return <p>Loading</p>;

  return (
    <Layout>
      <h1>{inputNames?.findFormByID.name}</h1>
     
    </Layout>
  );
}

更新:我尝试将 useTable 移动到它自己的组件并将值作为道具传递并检查这些值是否首先存在。这仍然导致map is undefined错误,但是没有未定义的console.logs

...
  {headerColumns && colArrayData && (
        <Table headerColumns={headerColumns} colArrayData={colArrayData} />
      )}
...

表格组件

const Table = ({ headerColumns, colArrayData }) => {
  console.log(headerColumns);

  console.log(colArrayData);


  //THIS PART BREAKS THE CODE
  const tableInstance = useTable({ headerColumns, colArrayData });

  return (
    <div>
      <h1>Table</h1>
    </div>
  );
};

更新:这是我最近一次无济于事的尝试,并且没有未定义的控制台日志,所以不确定为什么 useTable 会出现这个问题



const Table = ({ data, inputDataState }) => {
  const header = inputDataState?.map((item, i) => {
    return { Header: item.name, accessor: `col${i}` };
  });

  const headerColumns = React.useMemo(() => header, []);

  const well = data?.data?.map((item, i) => {
    delete item.data["FormID"];
    delete item.data["user"];
    delete item.data["visible"];
    delete item.data["sheetName"];
    item.data["refId"] = item.ref["@ref"].id;
    const ok = Object.values(item.data);
    const ref = item.ref["@ref"].id;

    //console.log(ok);

    return ok?.map((value, i) => {
      return { [`col${i}`]: value };
    });
  });

  const result = well?.map((a) => Object.assign({}, ...a));

  const colArrayData = React.useMemo(() => result, []);

  console.log(headerColumns);

  console.log(colArrayData);

  const tableInstance = useTable({ headerColumns, colArrayData });

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
  } = tableInstance;

  return (
    <table {...getTableProps()}>
      <thead>
        {
          // Loop over the header rows
          headerGroups.map((headerGroup) => (
            // Apply the header row props
            <tr {...headerGroup.getHeaderGroupProps()}>
              {
                // Loop over the headers in each row
                headerGroup.headers.map((column) => (
                  // Apply the header cell props
                  <th {...column.getHeaderProps()}>
                    {
                      // Render the header
                      column.render("Header")
                    }
                  </th>
                ))
              }
            </tr>
          ))
        }
      </thead>
      {/* Apply the table body props */}
      <tbody {...getTableBodyProps()}>
        {
          // Loop over the table rows
          rows.map((row) => {
            // Prepare the row for display
            prepareRow(row);
            return (
              // Apply the row props
              <tr {...row.getRowProps()}>
                {
                  // Loop over the rows cells
                  row.cells.map((cell) => {
                    // Apply the cell props
                    return (
                      <td {...cell.getCellProps()}>
                        {
                          // Render the cell contents
                          cell.render("Cell")
                        }
                      </td>
                    );
                  })
                }
              </tr>
            );
          })
        }
      </tbody>
    </table>
  );
};

const fetcher = (url) => fetch(url).then((r) => r.json());

export default function FormData() {
  const { data: cookieData, error: cookieError } = useSWR(
    "/api/cookie",
    fetcher
  );
  const Router = useRouter();
  const { data, error } = useSWR([`/api/data`, Router.query.id], fetchWithId);

  var test = `Bearer ${cookieData}`;

  const { loading, error: inputError, data: inputNames } = useQuery(
    INPUT_VALUES,
    {
      variables: { id: Router.query.id },
      context: {
        headers: {
          authorization: test,
        },
      },
      skip: !test,
    }
  );

  const [inputDataState, setInputDataState] = useState([]);

  useEffect(() => {
    const inputData = inputNames?.findFormByID?.formInputVals?.data;
    // let arr = [...inputData, { name: "Sheet Add" }];
    // console.log(arr);
    setInputDataState(inputData);
  }, [inputNames]);



  if (!data || loading) return <p>Loading</p>;

  return (
    <Layout>
      <h1>{inputNames?.findFormByID.name}</h1>

      {data && inputDataState && (
        <Table data={data} inputDataState={inputDataState} />
      )}
    </Layout>
  );
}

更新:最后我尝试在 React.useMemo 中移动地图函数,但仍然得到同样的错误。

const headerColumns = React.useMemo(() => {
    return inputDataState?.map((item, i) => {
      return { Header: item.name, accessor: `col${i}` };
    });
  }, []);

  const colArrayData = React.useMemo(() => {
    const well = data?.data?.map((item, i) => {
      delete item.data["FormID"];
      delete item.data["user"];
      delete item.data["visible"];
      delete item.data["sheetName"];
      item.data["refId"] = item.ref["@ref"].id;
      const ok = Object.values(item.data);
      const ref = item.ref["@ref"].id;

      //console.log(ok);

      return ok?.map((value, i) => {
        return { [`col${i}`]: value };
      });
    });

    return well?.map((a) => Object.assign({}, ...a));
  }, []);

  console.log(headerColumns);

  console.log(colArrayData);

  const tableInstance = useTable({ headerColumns, colArrayData });
   // cannot read propery map of undefined

标签: javascriptreactjsreact-tableside-effectsreact-usememo

解决方案


推荐阅读