I am new to react-table
and trying to re-render a react-table
when data
supplied to it changes. Is there anyway to do so? I have tried using useEffect() with no avail.
CLARIFICATION: Usage.js
and Updater.js
needs to be kept seperated with their functions as shown. I am open to using another approach than global variable if it can help rerender the table when the data value changes.
table.js
import React, {useMemo} from 'react'
import {useTable} from 'react-table'
export const Table = ({ columns, data, noDataComponent, rest }) => {
const tableColumns = useMemo(() => columns, [columns]);
const { getTableBodyProps, getTableProps, headerGroups, prepareRow, rows } = useTable({ columns: tableColumns, data });
if (!rows.length) {
if (noDataComponent) return noDataComponent;
return <>No data</>;
}
React.useEffect(() => {}, [data]) //does not re-render table
return (
<table {getTableProps()} {rest}>
<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) => {
const { className, style } = cell.column;
return (
<td {cell.getCellProps({ className, style })}>
{cell.render('Cell')}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
};
globalVariable.js
module.exports = global.config = {
value: { exactval: [] }
}
Usage.js
data
is updated by using a GET request in Updater.js and supplied using global variable in globalVariable.js.
import {Table} from './table.js'
<Table data={global.config.value.exactval} columns={COLS} />
Updater.js
import './globalVariable.js'
function DummyCall() { //Works fine
axios.get(URL, headers)
.then(reponse => {
global.config.value.exactval.push(reponse.ID[1])
}
).catch(error => {
console.log(error)
}) }
<button type ="button" onClick={() => DummyCall()} > Test me! </button>
A simple explaination with example code would be greatly appreciated.
EDIT #1: Added how data is updated
EDIT #2:
After taking the advice of @Obsidianlab and @Johnny, I used Context API using Johnny’s answer (there is an important bug in answer where needs to wrap the .Provider
in return()
, I am getting the following strange behaviour:
Updater.js
Updated based on @Johnny’s steps
import './globalVariable.js'
function DummyCall() { //Works fine
const updatedData = { context.data };
axios.get(URL, headers)
.then(reponse => {
global.config.value.exactval.push(reponse.ID[1])
updatedData.data.push(reponse.ID[1]);
}
context.setData(updatedData)
).catch(error => {
console.log(error)
}) }
<button type ="button" onClick={() => DummyCall()} > Test me! </button>
For Usage.js
The following code below works and re-renders:
const context = useContext(TableDataContext) //needs to be there
<Table data={global.config.value.exactval} columns={COLS} />
The following code below does NOT re-render, however console says that the context.data.exactval
value is updated.
const context = useContext(TableDataContext);
<Table data={context.data.exactval} columns={COLS} />
How can i fix non-render issue related to Context API?
Advertisement
Answer
So, from my understanding, you are updating a global variable created in a js file ./globalVariable.js
. I haven’t seen the file, but I believe these variables are outside the scope of what react can “keep an eye on”.
So I suggest you to create a state for your data in the Usage.js
, and then update it. Example:
Usage.js
import { Table } from './table.js';
const [data, setData] = useState(initialData); //define your inital data like your global variables
async function DummyCall() {
try {
const response = await axios.get(URL, headers);
if(response.status === 200) {
const updatedData = { data };
updatedData.config.value.exactval.push(reponse.ID[1]);
setData(updatedData)
}
} catch(error) {
console.log(error);
}
}
<button type ="button" onClick={() => DummyCall()} > Test me! </button>
Edit #1
Since you cannot merge both files or export the function, i suggest you tu use ContextAPI
TableDataContext.js
import { createContext } from 'react'
const TableDataContext = createContext();
const TableDataProvider = ({ children }) => {
const [data, setData] = useState(initialData); //define your inital
<TableDataContext.Provider value={{ data, setData }}>
{children}
</TableDataContext.Provider>
}
export { TableDataContext, TableDataProvider };
Now you have to wrap your components taht need to consume the TableDataContext
with the provider
If you want in your whole app, for example:
import { TableDataProvider } from 'path/to/context/TableDataContext'
<TableDataProvider>
<App/>
</TableDataProvider>
This way, you can setData
in DummyCall
by importing from context:
Updater.js
import { useContext } from 'react';
import { TableDataContext } from 'path/to/context/TableDataContext'
.
const context = useContext(TableDataContext);
async function DummyCall() {
//...code
// on setData
const updatedData = { context.data };
updatedData.config.value.exactval.push(reponse.ID[1]);
context.setData(updatedData)
}
Finally just import the data from context in your table.js
, and you will not need to pass by props
You can learn more about the ContextAPI on React Docs
Hope it works