I’m very naive to ReactJS, in below code, in columns editorCellRenderer, there is a button onClick function, which uses rowsData of useState, so after fetching data from api, I update
rowsData using setRowsData, but in button rowsData always remains []. Because of this after edit of any column data, it is not reflected in UI.
section of code I’m referring:
<button
style={{ marginLeft: 10, marginRight: 20 }}
onClick={async (e) => {
console.log({ rowsData });
let rowsClone = [...rowsData];
let updatedRowIndex = rowsClone.findIndex(
(r) => r.id === data.id
);
rowsClone[updatedRowIndex] = data;
setRowsData(rowsClone);
tableManager.rowEditApi.setEditRowId(null);
}}
>
✔
</button>
App.js
import React, { useEffect, useState } from "react";
import GridTable from "@nadavshaar/react-grid-table";
// import data from "./data.json";
import "./styles.css";
const convertData = (response, from = 0) => {
const rawData = response.data.nutritionData.data;
return rawData.map((raw, index) => {
const obj = {
id: from + index + 1,
_id: raw._id,
Index: from + index + 1,
ENERC_KCAL: raw.ENERC_KCAL.qty,
totalWeight: raw.totalWeight.qty,
FAT: raw.macro_nutrients.FAT.qty,
FASAT: raw.macro_nutrients.FASAT.qty,
FATRN: raw.macro_nutrients.FATRN.qty,
CHOCDF: raw.macro_nutrients.CHOCDF.qty,
FIBTG: raw.macro_nutrients.FIBTG.qty,
SUGAR: raw.macro_nutrients.SUGAR.qty,
PROCNT: raw.macro_nutrients.PROCNT.qty,
CHOLE: raw.micro_nutrients.CHOLE.qty,
NA: raw.micro_nutrients.NA.qty,
CA: raw.micro_nutrients.CA.qty,
MG: raw.micro_nutrients.MG.qty,
K: raw.micro_nutrients.K.qty,
FE: raw.micro_nutrients.FE.qty,
ZN: raw.micro_nutrients.ZN.qty,
P: raw.micro_nutrients.P.qty,
VITA_IU: raw.micro_nutrients.VITA_IU.qty,
VITC: raw.micro_nutrients.VITC.qty,
THIA: raw.micro_nutrients.THIA.qty,
RIBF: raw.micro_nutrients.RIBF.qty,
NIA: raw.micro_nutrients.NIA.qty,
VITB6A: raw.micro_nutrients.VITB6A.qty,
VITB12: raw.micro_nutrients.VITB12.qty,
VITD: raw.micro_nutrients.VITD.qty,
TOCPHA: raw.micro_nutrients.TOCPHA.qty,
VITK1: raw.micro_nutrients.VITK1.qty,
healthLabels: raw.healthLabels,
cautions: raw.cautions,
brand: raw.brand,
title: raw.title
};
return obj;
})
}
const AsyncTable = () => {
let [rowsData, setRowsData] = useState([]);
const columns = [
{
id: 0,
field: "Index",
label: "Index",
width: "max-content"
},
{
id: 31,
field: "title",
label: "title",
width: "max-content"
},
{
id: 1,
field: "ENERC_KCAL",
label: "ENERC_KCAL",
width: "max-content"
},
{
id: 2,
field: "totalWeight",
label: "totalWeight",
width: "max-content"
},
{
id: 3,
field: "FAT",
label: "FAT",
width: "max-content"
},
{
id: 4,
field: "FASAT",
label: "FASAT",
width: "max-content"
},
{
id: 5,
field: "FATRN",
label: "FATRN",
width: "max-content"
},
{
id: 6,
field: "CHOCDF",
label: "CHOCDF",
width: "max-content"
},
{
id: 7,
field: "FIBTG",
label: "FIBTG",
width: "max-content"
},
{
id: 8,
field: "SUGAR",
label: "SUGAR",
width: "max-content"
},
{
id: 9,
field: "PROCNT",
label: "PROCNT",
width: "max-content"
},
{
id: 10,
field: "CHOLE",
label: "CHOLE",
width: "max-content"
},
{
id: 11,
field: "NA",
label: "NA",
width: "max-content"
},
{
id: 12,
field: "CA",
label: "CA",
width: "max-content"
},
{
id: 13,
field: "MG",
label: "MG",
width: "max-content"
},
{
id: 14,
field: "K",
label: "K",
width: "max-content"
},
{
id: 15,
field: "FE",
label: "FE",
width: "max-content"
},
{
id: 16,
field: "ZN",
label: "ZN",
width: "max-content"
},
{
id: 17,
field: "P",
label: "P",
width: "max-content"
},
{
id: 18,
field: "VITA_IU",
label: "VITA_IU",
width: "max-content"
},
{
id: 19,
field: "VITC",
label: "VITC",
width: "max-content"
},
{
id: 20,
field: "THIA",
label: "THIA",
width: "max-content"
},
{
id: 21,
field: "RIBF",
label: "RIBF",
width: "max-content"
},
{
id: 22,
field: "NIA",
label: "NIA",
width: "max-content"
},
{
id: 23,
field: "VITB6A",
label: "VITB6A",
width: "max-content"
},
{
id: 24,
field: "VITB12",
label: "VITB12",
width: "max-content"
},
{
id: 25,
field: "VITD",
label: "VITD",
width: "max-content"
},
{
id: 26,
field: "TOCPHA",
label: "TOCPHA",
width: "max-content"
},
{
id: 27,
field: "VITK1",
label: "VITK1",
width: "max-content"
},
{
id: 28,
field: "healthLabels",
label: "healthLabels"
},
{
id: 29,
field: "cautions",
label: "cautions"
},
{
id: 30,
field: "brand",
label: "brand"
},
{
id: "my-buttons-column",
width: "max-content",
pinned: true,
sortable: false,
resizable: false,
cellRenderer: ({
tableManager,
value,
data,
column,
colIndex,
rowIndex
}) => (
<button
style={{ marginLeft: 20 }}
onClick={(e) => tableManager.rowEditApi.setEditRowId(data.id)}
>
✎
</button>
),
editorCellRenderer: ({
tableManager,
value,
data,
column,
colIndex,
rowIndex,
onChange
}) => (
<div style={{ display: "inline-flex" }}>
<button
style={{ marginLeft: 20 }}
onClick={(e) => tableManager.rowEditApi.setEditRowId(null)}
>
✖
</button>
<button
style={{ marginLeft: 10, marginRight: 20 }}
onClick={async (e) => {
console.log({ rowsData });
let rowsClone = [...rowsData];
let updatedRowIndex = rowsClone.findIndex(
(r) => r.id === data.id
);
rowsClone[updatedRowIndex] = data;
setRowsData(rowsClone);
tableManager.rowEditApi.setEditRowId(null);
}}
>
✔
</button>
</div>
)
}
]
const onRowsRequest = async (requestData, tableManager) => {
const limit = requestData.to - requestData.from;
const page = Math.floor(requestData.from / limit) + 1;
const response = await fetch('http://localhost:4000/api/v0/noauth/get/nutrition', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
limit,
page
})
});
const jsonData = await response.json();
const rows = convertData(jsonData, requestData.from);
const totalRows = jsonData.data.nutritionData.totalDocuments;
setRowsData(rows);
return {
rows,
totalRows
};
};
return (
<div className="App">
<GridTable
pageSizes={[10, 20, 30, 40, 50, 100]}
columns={columns} onRowsRequest={onRowsRequest} />
</div>
);
};
export default AsyncTable;
App.css
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
data.json to mimic actual api data:
{
"status": "success",
"code": "0000",
"data": {
"nutritionData": {
"totalDocuments": 667888,
"totalPages": 66789,
"data": [
{
"ENERC_KCAL": {
"code": 208,
"label": "Energy",
"qty": 2905.88,
"unit": "kcal"
},
"totalWeight": {
"label": "weight",
"qty": 1906.75,
"unit": "g"
},
"_id": "ea553309-53ee-41dd-8a87-b1a7aa138e72",
"macro_nutrients": {
"FAT": {
"code": 204,
"label": "TOTAL_Fat",
"qty": 181.32,
"unit": "g"
},
"FASAT": {
"code": 606,
"label": "Saturated",
"qty": 92.62,
"unit": "g"
},
"FATRN": {
"code": 605,
"label": "Trans",
"qty": 4.8,
"unit": "g"
},
"CHOCDF": {
"code": 205,
"label": "Carbs",
"qty": 220.47,
"unit": "g"
},
"FIBTG": {
"code": 291,
"label": "Fiber",
"qty": 16.96,
"unit": "g"
},
"SUGAR": {
"code": 269,
"label": "Sugars",
"qty": 43.6,
"unit": "g"
},
"PROCNT": {
"code": 203,
"label": "Protein",
"qty": 98.03,
"unit": "g"
}
},
"micro_nutrients": {
"CHOLE": {
"code": 601,
"label": "Cholesterol",
"qty": 427.81,
"unit": "mg"
},
"NA": {
"code": 307,
"label": "Sodium",
"qty": 2874.8,
"unit": "mg"
},
"CA": {
"code": 301,
"label": "Calcium",
"qty": 2401.52,
"unit": "mg"
},
"MG": {
"code": 304,
"label": "Magnesium",
"qty": 293.34,
"unit": "mg"
},
"K": {
"code": 306,
"label": "Potassium",
"qty": 3371.02,
"unit": "mg"
},
"FE": {
"code": 303,
"label": "Iron",
"qty": 4.28,
"unit": "mg"
},
"ZN": {
"code": 309,
"label": "Zinc",
"qty": 13.51,
"unit": "mg"
},
"P": {
"code": 305,
"label": "Phosphorus",
"qty": 2288.82,
"unit": "mg"
},
"VITA_IU": {
"code": 318,
"label": "Vitamin A",
"qty": 3073.58,
"unit": "iu"
},
"VITC": {
"code": 401,
"label": "Vitamin C",
"qty": 24.98,
"unit": "mg"
},
"THIA": {
"code": 404,
"label": "Thiamin (B1)",
"qty": 1.02,
"unit": "mg"
},
"RIBF": {
"code": 405,
"label": "Riboflavin (B2)",
"qty": 2.35,
"unit": "mg"
},
"NIA": {
"code": 406,
"label": "Niacin (B3)",
"qty": 13.12,
"unit": "mg"
},
"VITB6A": {
"code": 415,
"label": "Vitamin B6",
"qty": 1.78,
"unit": "mg"
},
"VITB12": {
"code": 418,
"label": "Vitamin B12",
"qty": 4.95,
"unit": "mcg"
},
"VITD": {
"code": 324,
"label": "Vitamin D",
"qty": 368.7,
"unit": "mcg"
},
"TOCPHA": {
"code": 323,
"label": "Vitamin E",
"qty": 9.81,
"unit": "mg"
},
"VITK1": {
"code": 430,
"label": "Vitamin K",
"qty": 42.5,
"unit": "mcg"
}
},
"healthLabels": [
"FISH_FREE",
"RED_MEAT_FREE",
"PEANUT_FREE",
"MUSTARD_FREE",
"GLUTEN_FREE",
"SESAME_FREE",
"SOY_FREE",
"TREE_NUT_FREE"
],
"cautions": [
"DAIRY"
],
"supported_serving_units": [
{
"label": "serving",
"unit_weight": "263.0",
"qty": "1"
},
{
"label": "grams",
"unit_weight": 1,
"qty": 1
}
],
"ingredients": [
{
"input": {
"text": "cups milk",
"qty": [
"2",
"1/2"
]
},
"ingredient": "milk",
"unit": "cup",
"qty": 2.5,
"matched_ingredient": "milk",
"weight": 610,
"nutrition": {
"protein": 19.215,
"fat": 19.825,
"carbs": 29.279999999999998,
"sodium": 262.3
}
},
{
"input": {
"text": "cups water",
"qty": [
"1",
"1/2"
]
},
"ingredient": "water",
"unit": "cup",
"qty": 1.5,
"matched_ingredient": "water",
"weight": 360,
"nutrition": {
"protein": 0,
"fat": 0,
"carbs": 0,
"sodium": 14.4
}
},
{
"input": {
"text": "cup butter",
"qty": [
"1/4"
]
},
"ingredient": "butter",
"unit": "cup",
"qty": 0.25,
"matched_ingredient": "butter",
"weight": 56.75,
"nutrition": {
"protein": 0.482375,
"fat": 46.029925,
"carbs": 0.03405,
"sodium": 364.9025
}
},
{
"input": {
"text": "mashed potatoes 1 box",
"qty": []
},
"ingredient": "potatoes",
"unit": "box",
"qty": 1,
"matched_ingredient": "potato",
"weight": 100,
"nutrition": {
"protein": 2.02,
"fat": 0.09,
"carbs": 17.47,
"sodium": 6
}
},
{
"input": {
"text": "can kernel corn",
"qty": [
"1"
]
},
"ingredient": "kernel corn",
"unit": "can",
"qty": 1,
"matched_ingredient": "corn kernel",
"weight": 300,
"nutrition": {
"protein": 10.86,
"fat": 4.26,
"carbs": 77.61,
"sodium": 12
}
},
{
"input": {
"text": "cup cheddar cheese",
"qty": [
"1"
]
},
"ingredient": "cheddar cheese",
"unit": "cup",
"qty": 1,
"matched_ingredient": "cheddar cheese",
"weight": 240,
"nutrition": {
"protein": 57.696,
"fat": 81.16799999999999,
"carbs": 3.192,
"sodium": 1545.6
}
},
{
"input": {
"text": "cup French fried onions",
"qty": [
"1"
]
},
"ingredient": "french fried onions",
"unit": "cup",
"qty": 1,
"matched_ingredient": "french fries",
"weight": 240,
"nutrition": {
"protein": 7.752,
"fat": 29.951999999999998,
"carbs": 92.88000000000001,
"sodium": 669.6
}
}
],
"source": "food.com",
"brand": "",
"img_url": [],
"title": "crunchy onion potato bake",
"actualTitle": "Crunchy Onion Potato Bake",
"url": "http://www.food.com/recipe/crunchy-onion-potato-bake-479149",
"updatedAt": "2023-06-22T06:51:01.844Z"
}]
"displayMessage": "Successful"
}
I tried using useEffect and update button onClick function whenever state of rowsData changes. It didnt work.
I’m expecting to have rowsData in button onClick to be changed when I fetch api data and setRowsData in api call.
2
Answers
Though answer by @AhmedSbai totally worked fine and I found it better than solution provided by chatgpt, just for information I want to show solution given by chatGPT, after trying 30+ solutions and wasting 2-3 days, only one worked for me.
In Async Table: ` const rowsDataRef = useRef(rowsData);
In editorCellRenderer:
If you want to update a state based on its previous value, better is to do it with the functional state update:
this way
prev
will always provide you with the current value of the state, and what you return is what you give as a new value to it. here we return an array fromprev
mapping through each element returningdata
if the condition is met,row
otherwise.