React Table w/JSON API 钩子?

React Table w/JSON API hooks?

所以我开始学习使用 React Table (https://github.com/tannerlinsley/react-table) 它非常漂亮。然而,我是 React 的中级水平(我了解基本的 lifecycle/props/etc..)但是 hooks 对我来说是相当新的。

我决定将它用在一个主要是 classes 的个人项目中。它调用 API(我在 Rails 中写的)到 return 一些基本的 JSON 信息。我正在使用 axios (https://github.com/axios/axios) 调用 API.

通过学习 React Hook,我将原来的 componentDidMount() 调用转换为 useEffect() 调用。下面是 Table 和 Table 容器的代码(它用于处理传感器的应用程序,因此得名)

传感器容器:

import React, { useState, useEffect } from "react";
import axios from "axios";
import SensorCard from "./SensorCard";
import SensorTable from "./SensorTable";
import "../Styles/Components/_SensorContainer.css";

function SensorContainer() {
  const [sensors, setSensors] = useState([]);
  const [data, setData] = useState([])

  useEffect(() => {
    // GET sensor list from API
    axios
    .get("http://localhost:3000/api/v1/devices.json")
    .then((response) => {
      // handle success
      console.log(response);
      setSensors(response.data.data)
    })
    .then(() => {
      console.log(sensors)
      console.log(sensors[0].attributes)
      console.log(name)
      console.log(serialNumber)
      console.log(deviceStatus)
      const { name, 'serial-number':serialNumber, 'device-status':deviceStatus} = sensors[0].attributes
      const data = sensors.map(sensor => 
        ({ 
          id: sensor.id, 
          name: name, 
          serialNum: serialNumber,
          status: deviceStatus
        })
      )
    setData(data)
    })
    .catch((error) => {
      console.log(error);
    })
  }, [sensors.length]);





  // const data = React.useMemo(
  //   () => [
  //     {
  //       id: '1',
  //       name: 'TEMP001',
  //       serialNum: 'Temp Sensor',
  //       status: 'Active',
  //     },
  //     {
  //       id: '2',
  //       name: 'TEMP002',
  //       serialNum: 'Temp Sensor',
  //       status: 'Unknown',
  //     },
  //     {
  //       id: '3',
  //       name: 'HUM001',
  //       serialNum: 'Humidity Sensor',
  //       status: 'Active',
  //     },
  //   ],
  //   []
  // )

  const columns = React.useMemo(
    () => [
      {
        Header: 'ID',
        accessor: 'id', // accessor is the "key" in the data
      },
      {
        Header: 'Name',
        accessor: 'name',
      },
      {
        Header: 'Serial Number',
        accessor: 'serialNum',
      },
      {
        Header: 'Status',
        accessor: 'status',
      },
    ],
    []
  )
  return (
    <div>
      <SensorTable columns={columns} data={data} />
    </div>
  )
}

export default SensorContainer;

传感器Table:

import React from "react";
import {
  useTable,
  useGroupBy,
  useFilters,
  useSortBy,
  useExpanded,
  usePagination,
} from "react-table";
import "../Styles/Components/_SensorTable.css";

function SensorTable({ columns, data }) {
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
  } = useTable({ columns, data })

  // Render the UI for your table
  return (
    <table {...getTableProps()} style={{ border: 'solid 1px blue' }}>
      <thead>
        {headerGroups.map(headerGroup => (
          <tr {...headerGroup.getHeaderGroupProps()}>
            {headerGroup.headers.map(column => (
              <th
                {...column.getHeaderProps()}
                style={{
                  borderBottom: 'solid 3px red',
                  background: 'aliceblue',
                  color: 'black',
                  fontWeight: 'bold',
                }}
              >
                {column.render('Header')}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody {...getTableBodyProps()}>
        {rows.map(row => {
          prepareRow(row)
          return (
            <tr {...row.getRowProps()}>
              {row.cells.map(cell => {
                return (
                  <td
                    {...cell.getCellProps()}
                    style={{
                      padding: '10px',
                      border: 'solid 1px gray',
                      background: 'papayawhip',
                    }}
                  >
                    {cell.render('Cell')}
                  </td>
                )
              })}
            </tr>
          )
        })}
      </tbody>
    </table>
  )
}

export default SensorTable;

所以我 运行 对此有一些 "design issues":

  1. How/Where 做人正常 set/store 列数据和 "data" 使用 React 时的数据 table。我假设只有一个 const 列....但是数据存储在哪里? (我通常会把它存放在 在 class 中声明,但由于我尝试使用挂钩,所以我不确定)
  2. 我觉得我的 useEffect() 获取 API 数据是错误的。我还 运行 遇到了一个错误,它一直保持 运行。我看到有人建议检查长度以防止出现这种情况……但这感觉很老套。正确的做法是什么?
  3. 我不太明白如何用 React.useMemo 映射数据,我也找不到任何示例(显然 React table 需要这个)。有什么建议吗?

我真的不确定如何正确设置它。我似乎找不到任何使用 react table WITH json api 的人的例子。

除了一些修改之外,您的代码没有问题。你可以找到最终代码 here

  1. How/Where 做人正常 set/store 列数据和 "data" 使用 React 时的数据 table。我假设只有 const 列....但是数据存储在哪里? (我通常会把它存放在 在 class 中声明,但由于我尝试使用挂钩,所以我不确定)

    回答

    • 根据申请要求而定。
    • 如果数据需要在客户端持久化并在多个 modules/components 之间共享,那么使用 redux 来存储您的数据。
    • 如果只有在用户访问屏幕时才需要数据(不保存很长时间运行),则将数据保持在组件状态 .
  2. 我觉得我的 useEffect() 获取 API 数据是错误的。我还 运行 遇到了一个错误,它一直保持 运行ning。我看到有人建议检查长度以防止出现这种情况……但这感觉很老套。正确的做法是什么?

    回答

    • 根据您的代码,在 useEffect 挂钩中没有 requirement/need 传递依赖项。 (发生这种情况是因为您试图在双组件状态下维护相同的数据,即 datasensors。但是没有必要- PS见上面的附件代码link。看看Conditionally filtering an effect
    • 如果你想运行只对挂载产生一次影响(componentDidMount),你可以传递一个空数组([])作为第二个参数。所以它永远不会重新运行s.
  3. 我不太明白如何用 React.useMemo 映射数据,我也找不到任何示例(显然反应 table 需要这个).有什么建议吗?

    回答:

    • 如何映射数据是什么意思?。想对来自 API 的响应对象做一些 t运行sformation 吗?。如果是,您可以使用任何 Javascript 内置方法,或者您可以使用像 ramda or lodash
    • 这样的第三方库
    • useMemo 在您的情况下不是必需的,因为您没有进行任何复杂的操作并且您的数据源是 API.
    • reactjs 文档中提到的关于 useMemohook
    • 的一些注释

Remember that the function passed to useMemo runs during rendering. Don’t do anything there that you wouldn’t normally do while rendering. For example, side effects belong in useEffect, not useMemo.

您的代码没有问题,除了在两个单独的组件状态变量中维护相同的数据外没有任何问题。

参考下面代码中标有<----的行

  // const [sensors, setSensors] = useState([]); No need to maintain same data in two state variables
  const [data, setData] = useState([])

  useEffect(() => {
    // GET sensor list from API
    axios
    .get("http://localhost:3000/api/v1/devices.json")
    // .then((response) => {  
    //  handle success
    //  console.log(response);
    //  setSensors(response.data.data)
    // }) <------- this is not required
    .then((response) => {
      // ......
      const data = response.data.data.map(sensor => 
        ({ 
          id: sensor.id, 
          name: sensor.name, 
          serialNum: sensor.serialNumber,
          status: sensor.deviceStatus
        })
      )
      setData(data)
    })
    .catch((error) => {
      console.log(error);
    })
//  }, [sensors.length]);
}, []); // <--------- like componentDidMount in classBased components 

在工作中添加了最终代码 codesandbox here