Reputation: 3231
So I started learning to use React Table (https://github.com/tannerlinsley/react-table) it's pretty nifty. However I am an intermediate at React (I understand the basic lifecycle/props/etc..) but hooks are rather new to me.
I decided to use it in a personal project which was mostly classes. It calls an API (that I wrote in Rails) to return some basic JSON information. I am using axios (https://github.com/axios/axios) to call the API.
From learning react hooks I converted what was originally my componentDidMount()
call into a useEffect()
call. Below is the code for the Table and the Table Container (it is for an application that deals with sensors hence the names)
Sensor 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;
Sensor 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;
So I am running into a few "design issues" regarding this:
const
for the
columns....but where is the data stored? (I'd normally store it in
state in a class, but since im trying to use hooks I am unsure)useEffect()
is wrong for fetching API data. I also ran into a bug where it constantly kept running. I saw someone suggest to check the length to prevent this....but this feels hacky. What's the correct way to do this?React.useMemo
I can't find any examples either (Apparently react table requires this). Any Advice?I am just really unsure how to set this up properly. I can't seem to find any examples of people using react table WITH json api fetching either.
Upvotes: 1
Views: 5596
Reputation: 1277
Your code is fine except for a few modifications. You can find the final code here
How/Where do people normally set/store the column data and "data"
data when using react table. I'd assume just a const
for the
columns....but where is the data stored? (I'd normally store it in
state in a class, but since im trying to use hooks I am unsure)
Answer
I feel like my useEffect()
is wrong for fetching API data. I also ran into a bug where it constantly kept running. I saw someone suggest to check the length to prevent this....but this feels hacky. What's the correct way to do this?
Answer:
[]
) as a second argument. So it never re-runs.I can't quite figure out how to map the data how I want to with React.useMemo
I can't find any examples either (Apparently react table requires this). Any Advice?
Answer:
useMemo
hookRemember 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.
Your code is fine and there are no issues, except maintaining the same data in two separate component state variables.
Refer to the lines marked with <----
in below code
// 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
Added final code in working codesandbox here
Upvotes: 3