I am having a few issues with functionality of a particular part of my application.
I have a functional component 'Review Rounds' in react which performs a axios.get request. The response is then used to setState of the 'rounds' array. This part works fine. Here is the response
[
{
"label": null,
"consent": false,
"users": [],
"videoLink": "Hospital.mp4",
"id": "1da10881-b27d-46a5-883e-02296c9a6ab8",
"roundId": "1da10881-b27d-46a5-883e-02296c9a6ab8",
"idConfirmed": false
},
{
"label": null,
"consent": false,
"users": [],
"videoLink": "Hospital.mp4",
"id": "2abac091-57f4-4dec-8c0a-7b370794b081",
"roundId": "2abac091-57f4-4dec-8c0a-7b370794b081",
"idConfirmed": false
},
{
"label": null,
"consent": false,
"users": [],
"videoLink": "Hospital.mp4",
"id": "b68724dc-36b2-41b3-b677-b7ff98bac875",
"roundId": "b68724dc-36b2-41b3-b677-b7ff98bac875",
"idConfirmed": false
},
{
"label": null,
"consent": false,
"users": [],
"videoLink": "Hospital.mp4",
"id": "ec99c8cf-d180-4e2a-a246-875f7342d867",
"roundId": "ec99c8cf-d180-4e2a-a246-875f7342d867",
"idConfirmed": false
}]
I then want to display one the videoLink and roundId attributes only in a table.
I have created a columns variable like this
//Table Cols
const columns = React.useMemo(
()=>[
{
Header:"videoLink",
accessor:"videoLink"
},
{
Header:"roundId",
accessor:"roundId"
},
],
[]
)
and then defined table props and passed in columns and rounds:
const{
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} =useTable({columns , rounds})
The problem I am having is that rounds (at this stage does not seem to contain any data) despite it previously containing all of the info I need.
Am I doing something incorrectly with the state? or useEffect Methods?
Below is the full code for this functional component:
const ReviewRounds = () => {
const [rounds, setRounds]=useState([]);
const fetchVids=()=>{
axios.get(process.env.REACT_APP_URL_All_ROUNDS)
.then(res=>{
console.log("Rounds", res.data)
setRounds(res.data)
});
};
useEffect(()=>{
fetchVids();
},[])
//Table Cols
const columns = React.useMemo(
()=>[
{
Header:"videoLink",
accessor:"videoLink"
},
{
Header:"roundId",
accessor:"roundId"
},
],
[]
)
const{
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} =useTable({columns , rounds})
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 blue',
background: 'aliceblue',
color: 'black',
fontWeight: 'normal',
}}
>
{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: 'aliceblue',
}}
>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
)
}
export default ReviewRounds;
The error Im getting is:
TypeError: Cannot read properties of undefined (reading 'forEach')
Would say your useTable hook doesn't expect to be passed rounds as the prop for the data, since the state code seems fine.
Try something like useTable({columns , rows: rounds}) or whatever the hook expects.
Related
I am running into an issue with trying to render a table in react using react table. I've narrowed the error down to the data variable around line 13 in figure 1.
When I hard code the data, as shown in figure 1, I have no issues and everything works fine. This hard coded array is a direct copy of the baselineData prop being passed into the PrectionsTable component.
My error only happens when the data object is changed to as shown in figure 2. Instead of the data being hard coded, I am spreading the baselineData prop data.
Figure 3 shows baselineData in react web dev tools and is in fact an array of objects located on the PredictionsTable.
The specific error I am making can be seen in figure 4.
Figure 1
import { useTable } from 'react-table';
import React from 'react';
import SpinnerCustom from '../Spinner.js';
export default function PredictionsTable({
predictions,
baselineData,
loading,
}) {
const checkIfValueIsNumberAndRound = (x) =>
typeof x === 'number' ? x.toFixed(2) : 'n/a';
const data = React.useMemo(() => {
return [
{
make_cut: 0.837075,
player_name: 'Finau, Tony',
top_10: 0.42559600288600297,
top_20: 0.5817631080031079,
top_5: 0.293940416666667,
win: 0.105025,
},
{
make_cut: 0.71215,
player_name: 'Day, Jason',
top_10: 0.228348582528583,
top_20: 0.366261590839716,
top_5: 0.136055932539683,
win: 0.0341,
},
{
make_cut: 0.719925,
player_name: 'Harman, Brian',
top_10: 0.223825056748807,
top_20: 0.366779750145688,
top_5: 0.12981958333333302,
win: 0.032675,
},
{
make_cut: 0.710225,
player_name: 'Montgomery, Taylor',
top_10: 0.21918973443223397,
top_20: 0.352992788086097,
top_5: 0.130785406746032,
win: 0.0324,
},
];
}, [baselineData]);
const columns = React.useMemo(
() => [
{
Header: 'Player',
accessor: 'player_name', // accessor is the "key" in the data
},
{
Header: 'Make Cut',
accessor: 'make_cut',
Cell: (props) =>
checkIfValueIsNumberAndRound(props.cell.row.original.make_cut),
},
{
Header: 'Top 20',
accessor: 'top_20',
Cell: (props) =>
checkIfValueIsNumberAndRound(props.cell.row.original.top_20),
},
{
Header: 'Top 10',
accessor: 'top_10',
Cell: (props) =>
checkIfValueIsNumberAndRound(props.cell.row.original.top_20),
},
{
Header: 'Top 5',
accessor: 'top_5',
Cell: (props) =>
checkIfValueIsNumberAndRound(props.cell.row.original.top_20),
},
{
Header: 'Win',
accessor: 'win',
Cell: (props) =>
checkIfValueIsNumberAndRound(props.cell.row.original.top_20),
},
],
[]
);
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable({ columns, data });
return loading ? (
<SpinnerCustom />
) : (
<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, i) => {
prepareRow(row);
return (
<tr key={i} {...row.getRowProps()}>
{row.cells.map((cell, y) => {
return (
<td
{...cell.getCellProps()}
key={y}
style={{
padding: '10px',
border: 'solid 1px gray',
background: 'papayawhip',
}}
>
{cell.render('Cell')}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
}
Figure 2
const data = React.useMemo(() => {
return [...baselineData];
}, [baselineData]);
Figure 3
Figure 4 (ERROR)
this problem may related to initial data for baseLineData.
change the usesState initialize:
const [baselineData, setBaselineData] = useState([]);
I am writing the react-table getting started with typescript, however I am getting an error on the data I am passing into my table function:
utils.js:15 Uncaught TypeError: columns.map is not a function
at linkColumnStructure (utils.js:15:1)
at useTable.js:150:1
at mountMemo (react-dom.development.js:17057:1)
at Object.useMemo (react-dom.development.js:17517:1)
at Object.useMemo (react.development.js:1645:1)
at useTable (useTable.js:149:1)
at Table (App.tsx:9:1)
at renderWithHooks (react-dom.development.js:16141:1)
at mountIndeterminateComponent (react-dom.development.js:20838:1)
at beginWork (react-dom.development.js:22342:1)
Being new to react/typescript pointers much appreciated on my App.tsx below, if I comment out the Table function the page loads, so I am doing something wrong with my types just not sure what.
import React from 'react';
import { useTable } from 'react-table';
import logo from './logo-main.svg';
import './App.css';
function Table(columns: any, data: any) : any
{
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>
)
}
function App() {
const data = React.useMemo(
() => [
{
col1: 'Hello',
col2: 'World',
},
{
col1: 'react-table',
col2: 'rocks',
},
{
col1: 'whatever',
col2: 'you want',
},
],
[]
)
const columns = React.useMemo(
() => [
{
Header: 'Column 1',
accessor: 'col1', // accessor is the "key" in the data
},
{
Header: 'Column 2',
accessor: 'col2',
},
],
[]
)
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>Edit <code>src/App.tsx</code> and save to reload!!!</p>
<a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">Learn React today </a>
<Table columns={columns} data={data} />
</header>
</div>
);
}
export default App;
You have
<Table columns={columns} data={data} />
so inside Table the columns and data are part of the first argument, the props object.
function Table({ columns, data }: any) : any
But you should really type your identifiers properly - using any completely defeats the purpose of using TypeScript. Proper typing will let you catch these sorts of problems earlier, during compilation.
type Column = { Header: string, accessor: string };
type Data = { col1: string, col2: string };
function Table({
columns,
data,
}: {
columns: Array<Column>,
data: Array<Data>
}) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({ columns, data });
// etc
(You don't need to note the return type when TypeScript can infer it automatically - omitting an explicit type when TS can infer it is much preferable to setting it to any)
Your Table function should be
function Table({columns: any, data: any}) : any
instead of
function Table(columns: any, data: any) : any
Because you are passing columns and data as props from here
<Table columns={columns} data={data} />
I am trying to get json data each second to add as a new row in my react table.
In the console it seems data is coming up each second but in the UI none of the data is popping up. Couldn't figure out why any of that table row in not being displayed. The snippet below does not work in stackoverflow please use the sandbox for running the code.
import React, { useState, useEffect } from "react";
import { useTable } from "react-table";
// import "./styles.css";
const API_DATA_RETURNED = [
{
// I tried id: "1" as well
id: "1",
name: "TEMP001",
serialNum: "Temp Sensor",
status: "Active",
},
{
id: "2",
name: "TEMP002",
serialNum: "Temp Sensor",
status: "Unknown",
},
{
id: "3",
name: "HUM003",
serialNum: "Humidity Sensor",
status: "Active",
},
{
id: "4",
name: "HUM004",
serialNum: "Humidity Sensor",
status: "Active",
},
{
id: "5",
name: "HUM005",
serialNum: "Humidity Sensor",
status: "Active",
},
];
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>
);
}
function SensorContainer() {
const [page, setPage] = useState(0);
const [sensors, setSensors] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
function loadData(index) {
console.log("loadData called");
let newData = sensors;
console.log(newData);
newData.push(API_DATA_RETURNED[index]);
setSensors(newData);
console.log(sensors);
setLoading(false);
}
setLoading(true);
// GET sensor list from API
const timer = window.setInterval(() => {
if (page < API_DATA_RETURNED.length) {
loadData(page);
setPage(page + 1);
}
}, 1000);
return () => window.clearInterval(timer);
}, [page, sensors]); // This is self is componentDidMount
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",
},
],
[]
);
if (sensors.length === 0 && !loading) {
return <div>No Senors data available</div>;
}
return (
<div>
{loading && <span>Please wait we are fetching data</span>}
<SensorTable columns={columns} data={sensors} />
</div>
);
}
export default function App() {
return <SensorContainer />;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Same CODE in sandbox
I have a React table (react-table) that takes in data from an api to populate the row cells. The data looks something like this:
const data = [{id: "6666", contact_id: "1", poc_id: "2", contact: "John Doe",
watersheds: "{12070104,12090301,12090401}"}, {id: "6667", contact_id: "2",
poc_id: "3", contact: "Sally Jones", watersheds: "{12070105,12090301}"}]
There could be more or less items depending on what the API request returns. My issue is that when the Watershed column is populated with the watershed data item, it includes the { ... }s. I want it to return 12070104,12090301,12090401 in the cell, not {12070104,12090301,12090401}. I know I can use replace or some other method to remove and replace the unwanted { }s:
data.map(item => (item.watersheds.replace(/{/gi, "").replace(/}/gi, "")))
or something similar, but since I adding the data to the table dynamically, I'm not sure how to remove the { }s before they are displayed in the table? My table looks something like this:
import React from 'react'
import styled from 'styled-components'
import { useTable } from 'react-table'
import makeData from './makeData'
const Styles = styled.div`
padding: 1rem;
table {
border-spacing: 0;
border: 1px solid black;
tr {
:last-child {
td {
border-bottom: 0;
}
}
}
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
`
function Table({ columns, data }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({
columns,
data,
})
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
)
}
function App() {
const columns = React.useMemo(
() => [
{
Header: 'ID',
accessor: 'id',
},
{
Header: 'CONTACT ID',
accessor: 'contact_id',
},
{
Header: 'POC ID',
accessor: 'age',
},
{
Header: 'NAME',
accessor: 'contact',
},
{
Header: 'Watersheds',
accessor: 'watersheds',
}
], []
)
//const data = React.useMemo(() => makeData(20), [])
const data = useMemo(() => [{id: "6666", contact_id: "1", poc_id: "2", contact: "John Doe",
watersheds: "{12070104,12090301,12090401}"}, {id: "6667", contact_id: "2",
poc_id: "3", contact: "Sally Jones", watersheds: "{12070105,12090301}"}])
return (
<Styles>
<Table columns={columns} data={data} />
</Styles>
)
}
export default App
You can render a custom content for each cell . Instead of transforming the data before passing to the table . we can just transform the value before rendering .
{
Header: "Watersheds",
accessor: "watersheds",
Cell: (props) => {
return <p>{props.value.replace(/{/gi, "").replace(/}/gi, "")}</p>;
}
}
Working Sandbox
In your App component, right before using useMemo, you can extract that array of objects to a separate varible, iterate over watersheds and replace them with the regex that you used above. After that you can pass it to useMemo.
I have a react table that looks like this.
I want to be able to click each individual cell and get the value. I know you can get the entire row, but I only want each individual cell when it's clicked so I can save it in state like this
{
"Team": GB,
"MoneyLine": -120
}
{
"Team": GB,
"Spread": 1
}
{
"Team": GB,
"MoneyLine": -120,
"Spread": -1,
"Total": 48
}
I tried this link How to get cell value on React-Table?
but it doesn't provide much explanation.
I need to get the team name whenever any cell in the row is clicked and then the specific value that is clicked.
Here is the code
import React, { useState } from 'react'
import styled from 'styled-components'
import { useTable } from 'react-table'
import data from '../Data/data.json'
const Styles = styled.div`
padding: 1rem;
table {
border-spacing: 0;
border: 1px solid black;
tr {
:last-child {
td {
border-bottom: 0;
}
}
}
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
`
function Table({ columns, data }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({
columns,
data,
})
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()} >{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()} >{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
)
}
export default function PicksTable(){
const [team, setTeam] = useState('');
const [moneyLine, setMoneyLine] = useState('');
const [spread, setSpread] = useState('');
const [total, setTotal] = useState('');
const columns = React.useMemo(
() => [
{
Header: 'Teams',
columns: [
{
Header: 'Team',
accessor: 'team',
},
],
},
{
Header: 'Betting Info',
columns: [
{
Header: 'Money Line',
accessor: 'moneyLine',
},
{
Header: 'Spread',
accessor: 'spread',
},
{
Header: 'Total',
accessor: 'total',
},
],
},
],
[]
)
return (
<Styles>
<Table columns={columns} data={data} />
</Styles>
)
}
You need to add onClick to <td> (values are in row and cell):
<td
onClick={() => console.info(row.values.team, cell.value)}
{...cell.getCellProps()}
>
Here is a full working CodeSandbox:
https://codesandbox.io/s/fervent-shape-jr8tm?file=/src/App.js:1325-1489