【问题标题】:React Table w/JSON API hooks?带有 JSON API 钩子的反应表?
【发布时间】:2020-04-22 03:10:55
【问题描述】:

所以我开始学习使用 React Table (https://github.com/tannerlinsley/react-table),它非常棒。但是我是 React 的中级人员(我了解基本的生命周期/道具/等等),但 hooks 对我来说相当新。

我决定在一个主要是课程的个人项目中使用它。它调用一个 API(我在 Rails 中编写)来返回一些基本的 JSON 信息。我正在使用 axios (https://github.com/axios/axios) 调用 API。

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

传感器容器:

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;

传感器表:

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;

所以我遇到了一些关于此的“设计问题”:

  1. 人们通常如何/在哪里设置/存储列数据和“数据” 使用反应表时的数据。我假设只是一个const 列....但是数据存储在哪里? (我通常会将其存储在 在课堂上陈述,但由于我试图使用钩子我不确定)
  2. 我觉得我的useEffect() 无法获取 API 数据。我还遇到了一个不断运行的错误。我看到有人建议检查长度以防止这种情况发生......但这感觉很糟糕。这样做的正确方法是什么?
  3. 我不太清楚如何使用React.useMemo 映射我想要的数据我也找不到任何示例(显然反应表需要这个)。有什么建议吗?

我真的不确定如何正确设置它。我似乎也找不到任何使用带有 json api 获取的反应表的人的例子。

【问题讨论】:

    标签: reactjs axios react-table


    【解决方案1】:

    您的代码很好,除了一些修改。可以找到最终代码here

    1. 人们通常如何/在哪里设置/存储列数据和“数据” 使用反应表时的数据。我假设只是一个const 列....但是数据存储在哪里? (我通常会将其存储在 在课堂上陈述,但由于我试图使用钩子我不确定)

      回答

      • 根据应用需求而定。
      • 如果数据需要在客户端持久化并在多个模块/组件之间共享,则使用 redux 来存储您的数据。
      • 如果仅在用户访问屏幕时才需要(不长期保存)数据,则将数据保持在组件状态
    2. 我觉得我的useEffect() 无法获取 API 数据。我还遇到了一个不断运行的错误。我看到有人建议检查长度以防止这种情况发生......但这感觉很糟糕。这样做的正确方法是什么?

      回答

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

      回答

      • 如何映射数据是什么意思?。想要对来自 API 的响应对象进行一些转换?如果是,您可以使用任何 Javascript 内置方法,也可以使用 3rd 方库,例如 ramdalodash
      • useMemo 在您的情况下不是必需的,因为您没有进行任何复杂的操作,并且您的数据源是 API。
      • reactjs 文档中提到了一些关于 useMemohook 的注释

    请记住,传递给 useMemo 的函数在渲染期间运行。 不要在那里做任何你在渲染时通常不会做的事情。 比如副作用属于useEffect,而不是useMemo。

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

    参考下面代码中标有&lt;----的行

      // 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中添加了最终代码

    【讨论】:

    • 谢谢!这非常有帮助。我很高兴我至少在正确的轨道上,但不必维护两个独立的组件状态对我来说应该是显而易见的哈!
    猜你喜欢
    • 1970-01-01
    • 2021-10-04
    • 2021-10-28
    • 2019-08-03
    • 1970-01-01
    • 2021-02-01
    • 1970-01-01
    • 2020-11-11
    • 2023-03-08
    相关资源
    最近更新 更多