'How do I update the parent JSON from child
I'm writing a React code in which I need to upload a CSV file, on click of a button, Create a new column, once I update a value there, update the JSON passed from parent to child. Currently, I'm able to upload files, create a column, edit the data and see the updated data in the child component.
However, I'm unable to understand how can I send it back to the parent. I should be able to see the updated date when I click Get Final Data
button. How can I send back data from child to parent?
Here is my code:
LoadFiles.js (parent)
import { useEffect, useState } from "react";
import RenderTable from "./RenderTable";
import Tab from "@mui/material/Tab";
import TabContext from "@mui/lab/TabContext";
import TabList from "@mui/lab/TabList";
import TabPanel from "@mui/lab/TabPanel";
const Load = () => {
const [files, setFiles] = useState([]);
const [allData, setAllData] = useState([]);
const [isDone, setIsDone] = useState(false);
const [processingData, setProcessingData] = useState(false);
const [value, setValue] = useState("1");
const [csvArray, setCsvArray] = useState([]);
const handleTabChange = (event, newValue) => {
setValue(newValue);
};
const processCSV = (str, fileName, delim = ",") => {
const headers = str.slice(0, str.indexOf("\r\n")).split(delim);
const rows = str.slice(str.indexOf("\r\n") + 1, str.length).split("\r\n");
let nArray = rows.map((row) => {
const values = row.split(delim);
const eachObj = headers.reduce((obj, header, i) => {
obj[header] = values[i];
return obj;
}, {});
return eachObj;
});
createKeys(nArray, fileName);
};
const createKeys = async (data, fileName) => {
const dataToSet = {
fileName: fileName,
keys: Object.keys(data.length ? data[0] : {}),
values: data.filter((o) => Object.keys(o).length)
};
console.log(JSON.stringify(dataToSet));
setAllData((prev) => [...prev, dataToSet]);
};
useEffect(() => {
if (
(files.length >= 1 && files.length === allData.length && !isDone) ||
processingData
) {
setIsDone(true);
}
}, [allData, isDone, files, processingData]);
useEffect(() => {
console.log(JSON.stringify(csvArray));
}, [csvArray]);
const handleUpload = (e) => {
Array.from(files).forEach((file) => {
const currFile = file;
const reader = new FileReader();
reader.onload = (e) => {
const text = e.target.result;
processCSV(text, file.name.split(".").slice(0, -1).join("."));
};
reader.readAsText(currFile);
});
};
const handleChange = (e) => {
e.preventDefault();
setFiles(e.target.files);
};
const processData = (e) => {
var currData = allData;
setAllData([]);
currData.forEach((item) => {
let rowWithSum = item.values.map((item1) => {
let newCol = item1["Rank"];
return {
...item1,
"New Col": newCol
};
});
createKeys(rowWithSum, item.fileName);
setProcessingData(true);
});
};
const getLink = () => {
console.log(JSON.stringify(allData));
};
return (
<div id="formWrapper">
<div id="centerContent">
<form id="csv-form">
<input
type="file"
accept=".csv"
id="csvFile"
multiple
onChange={(e) => handleChange(e)}
/>
<button
onClick={(e) => {
e.preventDefault();
handleUpload();
}}
>
Upload your csv
</button>
</form>
<button
className="processData"
onClick={(e) => {
e.preventDefault();
processData();
}}
>
Processdata
</button>
<button
onClick={(e) => {
e.preventDefault();
getLink();
}}
>
Get Final Data
</button>
</div>
{isDone && allData.length >= 1 && (
<TabContext value={value}>
<TabList onChange={handleTabChange}>
{files.length >= 1 &&
[...allData].map((item1, idx) => (
<Tab label={item1.fileName} value={`${idx + 1}`} />
))}
</TabList>
{files.length >= 1 &&
[...allData].map((item1, idx) => (
<TabPanel value={`${idx + 1}`}>
<RenderTable
keys={item1.keys}
csvArray={item1.values}
setCsvArray={setCsvArray}
></RenderTable>
</TabPanel>
))}
</TabContext>
)}
</div>
);
};
export default Load;
RenderTable.js (child)
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";
import { useEffect, useState } from "react";
const RenderTable = ({ csvArray, setCsvArray, keys }) => {
const [csvArrayState, setCsvArrayState] = useState(() => csvArray);
const handleBlur = (e) => {
e.currentTarget.classList.add("noBorder");
e.currentTarget.classList.remove("border");
setCsvArray(csvArrayState);
};
useEffect(() => {
setCsvArrayState(csvArray);
}, [csvArray]);
const handleChange = (e) => {
e.preventDefault();
e.currentTarget.readOnly = false;
e.currentTarget.classList.remove("noBorder");
e.currentTarget.classList.add("border");
};
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
{keys.map((item, idx) => (
<TableCell key={idx}>{item}</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{csvArray.map((item, i) => (
<TableRow>
{keys.map((key, idx) =>
key === "New Col" ? (
<TableCell>
<input
class="noBorder"
type="true"
readOnly="true"
value={csvArrayState[i]["New Col"]}
onChange={(e) => {
const updatedRankFields = csvArrayState.map(
(r, rIdx) => {
if (rIdx === i) {
return { ...r, "New Col": e.target.value };
} else {
return r;
}
}
);
setCsvArrayState(updatedRankFields);
}}
onBlur={(e) => handleBlur(e)}
onClick={(e) => handleChange(e)}
></input>
</TableCell>
) : (
<TableCell> {item[key]} </TableCell>
)
)}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
};
export default RenderTable;
How can I do this? Here is codesandbox link of the same. I've added the files under /Files.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|