如何绑定数据以做出反应 table

How to bind data to react table

我是第一次玩 React,我想连接(id、名称、状态和数量):

interface Goods {
  id: number;
  name: string;
  status: string;
  quantity?: number;
}

export const getGoods = (): Promise<Goods[]> => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: "A",
          status: "ready",
          quantity: 15
        },
        {
          id: 2,
          name: "B",
          status: "pending",
          quantity: 25
        },
        {
          id: 3,
          name: "C",
          status: "ready",
          quantity: 10
        },
        {
          id: 4,
          name: "D",
          status: "not ready",
          quantity: 25
        },
        {
          id: 5,
          name: "E",
          status: "ready",
          quantity: 25
        },
        {
          id: 6,
          name: "F",
          status: "ready",
          quantity: 5
        }
      ];

      resolve(data);
    }, 1000);
  });
};

到table正文:

import React from "react";
import { getGoods } from "./data";

export const Abc: React.FC = () => {
  return (
    <table className="table table-striped table-hover">
      <thead>
        <tr>
          <th scope="col">ID</th>
          <th scope="col">Name</th>
          <th scope="col">Status</th>
          <th scope="col">Quantity</th>
        </tr>
      </thead>

      <tbody>
        
      </tbody>

    </table>
  );
};

顶部的樱桃也将进行排序(例如按照以下顺序:准备好、未准备好、待定)。

感谢您的帮助或提示!

这里是沙盒:

https://codesandbox.io/s/recursing-torvalds-c343o

在你的table体内做类似的事情

<div className="table">
       {getGoods.data.map(goods=>(
           <tr>
               <td>{goods.id}</td>
               <td>{goods.name}</td>
               <td>{goods.status}</td>
                <td>{goods.quantity}</td>
           </tr>
       )
       )
       }
    </div>

正在加载数据

React 中的一切都围绕状态原则展开。您想使用 useState 挂钩将货物存储在状态中。

const [goods, setGoods] = React.useState<Goods[]>([]);

您将使用 useEffect 挂钩加载数据,并在 Promise 解析后将其保存到组件状态。你想要一个空的依赖数组 [] 到 运行 效果只有一次。

React.useEffect(() => {
  // need to define the function and call it separately
  const load = async () => {
    try {
      const data = await getGoods();
      setGoods(data);
    } catch (error) {
      // your Promise won't ever error, but an actual API might
    }
  };
  load();
}, []);

在您的 table 中,您遍历 goods 数组并为每个数组呈现一个 table 行 trmap 回调中的元素应该有一个唯一的 key 属性,所以我使用 id 作为键。 table 单元格 td 应遵循与您的列相同的顺序。

<tbody>
  {goods.map((item) => (
    <tr key={item.id}>
      <td>{item.id}</td>
      <td>{item.name}</td>
      <td>{item.status}</td>
      <td>{item.quantity}</td>
    </tr>
  ))}
</tbody>

正在排序

为了排序,您需要额外的状态来存储排序 属性 和排序顺序(升序或降序)。大概是这样的:

const [sortProperty, setSortProperty] = React.useState<keyof Goods>("id");

const [isDesc, setIsDesc] = React.useState(false);

单击您的列标题将更新这些状态。您可以将 sortPropertyisDesc 的当前值应用于 goods 数组,以便在渲染之前获得有序数组。

也许我们想在再次点击当前排序的列时反转顺序,但在点击不同的列时使用升序作为第一个排序。我们可能会创建一个这样的函数,我们可以将其用作 th 元素的 onClick 处理程序。

const handleColumnClick = (name: keyof Goods) => {
  const isCurrent = sortProperty === name;
  setSortProperty(name);
  setIsDesc(prev => isCurrent ? !prev : false);
}
<th scope="col" onClick={() => handleColumnClick("id")}>ID</th>

要应用订单,我们可以从 lodash's orderBy function 获得帮助。

const order = isDesc ? "desc" : "asc";
const rows = orderBy(goods, sortProperty, order);

我们想在 tbody 中使用这个有序变量 rows 而不是无序的 goods.


组件代码

Working Demo on CodeSandbox

import React from "react";
import { getGoods, Goods } from "./data";
import { orderBy } from "lodash";

export const Question3: React.FC = () => {
  const [goods, setGoods] = React.useState<Goods[]>([]);

  const [sortProperty, setSortProperty] = React.useState<keyof Goods>("id");
  const [isDesc, setIsDesc] = React.useState(false);

  const handleColumnClick = (name: keyof Goods) => {
    const isCurrent = sortProperty === name;
    setSortProperty(name);
    setIsDesc((prev) => (isCurrent ? !prev : false));
  };

  React.useEffect(() => {
    // need to define the function and call it separately
    const load = async () => {
      try {
        const data = await getGoods();
        setGoods(data);
      } catch (error) {
        // your Promise won't ever error, but an actual API might
      }
    };
    load();
  }, []);

  const order = isDesc ? "desc" : "asc";
  const rows = orderBy(goods, sortProperty, order);

  return (
    <table className="table table-striped table-hover">
      <thead>
        <tr>
          <th scope="col" onClick={() => handleColumnClick("id")}>
            ID
          </th>
          <th scope="col" onClick={() => handleColumnClick("name")}>
            Name
          </th>
          <th scope="col" onClick={() => handleColumnClick("status")}>
            Status
          </th>
          <th scope="col" onClick={() => handleColumnClick("quantity")}>
            Quantity
          </th>
        </tr>
      </thead>
      <tbody>
        {rows.map((item) => (
          <tr key={item.id}>
            <td>{item.id}</td>
            <td>{item.name}</td>
            <td>{item.status}</td>
            <td>{item.quantity}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
};

您的沙箱中有一个错误,混淆了默认导出和命名导出。应该是:

import {Question3 as Abc} from "./Table";

您还需要 export 您的 data.ts 文件中的 interface Goods 才能在您的组件中使用该类型。

getGoods 是承诺,需要时间来解决。直到那时显示加载器。

export const Abc: React.FC = () => {

const [loading, setLoading] = useState(false);
const [data, setData] = useState([]);
useEffect(() => {
    setLoading(true);
    (async () => {
        const dataResponse = await getGoods();
        setData(dataResponse);
    })().catch((e) => {
        console.error(e)
    }).finally(() => {
        setLoading(false);
    })
},[])
return (
    <table className="table table-striped table-hover">
        <thead>
            <tr>
                <th scope="col">ID</th>
                <th scope="col">Name</th>
                <th scope="col">Status</th>
                <th scope="col">Quantity</th>
            </tr>
        </thead>

        <tbody>
            {loading && <tr>
                <td colSpan='3'>Loading....</td>
            </tr>}
            {data.map(goods => (
                <tr>
                    <td>{goods.id}</td>
                    <td>{goods.name}</td>
                    <td>{goods.status}</td>
                    <td>{goods.quantity}</td>
                </tr>
                ))}
            </tbody>
        </table>
    );
};

这将帮助您确保在

中获得最终数据
const [data, setData] = useState([]);

我们如何从承诺中获取数据?使用

useState(handler, []) // [] so that is get called only once per component
const dataResponse = await getGoods(); // wait till promise resolves