英文:
UseState() is not updating on Button's onClick Method
问题
In the provided code, you are experiencing an issue where the rowsData
in the button's onClick
function doesn't reflect the updated data after fetching from the API and setting it using setRowsData
. To address this issue, you can try using the useEffect
hook to update the button's onClick
function whenever the rowsData
state changes. Here's how you can modify the code to achieve this:
import React, { useEffect, useState } from "react";
import GridTable from "@nadavshaar/react-grid-table";
import "./styles.css";
// ... (rest of the code)
const AsyncTable = () => {
let [rowsData, setRowsData] = useState([]);
// Add a useEffect to update the button's onClick function when rowsData changes
useEffect(() => {
const updatedColumns = [...columns];
const buttonColumn = updatedColumns.find(
(column) => column.id === "my-buttons-column"
);
if (buttonColumn) {
buttonColumn.editorCellRenderer = ({
tableManager,
value,
data,
column,
colIndex,
rowIndex,
onChange
}) => (
<div style={{ display: "inline-flex" }}>
<button
style={{ marginLeft: 20 }}
onClick={(e) => tableManager.rowEditApi.setEditRowId(data.id)}
>
✎
</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>
);
}
}, [rowsData]);
// ... (rest of the code)
};
With this modification, the useEffect
will monitor changes in the rowsData
state, and when it changes, it will update the onClick
function of the button column to ensure that it uses the most up-to-date rowsData
.
英文:
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);
}}
>
&#x2714;
</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)}
>
&#x270E;
</button>
),
editorCellRenderer: ({
tableManager,
value,
data,
column,
colIndex,
rowIndex,
onChange
}) => (
<div style={{ display: "inline-flex" }}>
<button
style={{ marginLeft: 20 }}
onClick={(e) => tableManager.rowEditApi.setEditRowId(null)}
>
&#x2716;
</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);
}}
>
&#x2714;
</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.
答案1
得分: 2
如果您想根据先前的值更新状态,最好使用函数式状态更新:
setRowsData((prev) =>
prev.map((row) => {
if (row.id === data.id) {
return data;
} else {
return row;
}
})
)
这样,prev
将始终为您提供状态的当前值,您返回的内容将作为新值提供给它。在这里,我们从 prev
返回一个数组,通过遍历每个元素,如果满足条件,则返回 data
,否则返回 row
。
英文:
If you want to update a state based on its previous value, better is to do it with the functional state update:
setRowsData((prev) =>
prev.map((row) => {
if (row.id === data.id) {
return data;
} else {
return row;
}
})
)
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 from prev
mapping through each element returning data
if the condition is met, row
otherwise.
答案2
得分: 1
尽管@AhmedSbai的回答完全有效,并且我发现比chatgpt提供的解决方案更好,但只是为了提供信息,我想展示chatGPT提供的解决方案,在尝试了30多种解决方案并浪费了2-3天之后,只有一种对我起作用。
在异步表中:
const rowsDataRef = useRef(rowsData);
useEffect(() => {
rowsDataRef.current = rowsData;
}, [rowsData]);
在editorCellRenderer中:
onClick={async (e) => {
let rowsClone = [...rowsDataRef.current];
let updatedRowIndex = rowsClone.findIndex(
(r) => r.id === data.id
);
rowsClone[updatedRowIndex] = data;
setRowsData(rowsClone);
tableManager.rowEditApi.setEditRowId(null);
}}
英文:
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);
useEffect(() => {
rowsDataRef.current = rowsData;
}, [rowsData]);`
In editorCellRenderer:
onClick={async (e) => {
let rowsClone = [...rowsDataRef.current];
let updatedRowIndex = rowsClone.findIndex(
(r) => r.id === data.id
);
rowsClone[updatedRowIndex] = data;
setRowsData(rowsClone);
tableManager.rowEditApi.setEditRowId(null);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论