I am facing issues with react-tabulator
library in ReactJS. when i try to use the ReactTabulator
component and pass the data
props value (which i have to get from redux store) the component throws an error ("MachineID" is read-only) [See ScreenShot for more detail]. i have tried TanStack table component as well and it works perfectly so i am not sure what i am doing wrong here!
Redux Libraries :
"react-redux": "^9.1.0"
"redux": "^5.0.1"
"@reduxjs/toolkit": "^2.2.1"
My Code:
import * as React from "react";
import { useSelector } from "react-redux";
import "react-tabulator/lib/styles.css"; // required styles
import "react-tabulator/lib/css/tabulator.min.css"; // theme
import { ReactTabulator } from "react-tabulator";
import { useEffect, useState } from "react";
const CostSheet = () => {
// TRY ONE
const { basic_costsheet } = useSelector((state) => state.qm.costsheet);
// TRY TWO
const [data, setData] = useState(basic_costsheet);
// TRY THREE
const mod_arr = basic_costsheet.map((e) => e);
// TRY FOUR
const mod_arr_two = [];
basic_costsheet.forEach((element) => {
mod_arr_two.push(element);
});
// TRY FIVE
const cs_data = [
{
McID: 1,
MachineID: "1",
MachineName: "m1",
MaxLength: 1020,
},
{
McID: 2,
MachineID: "2",
MachineName: "m2",
MaxLength: 1050,
},
{
McID: 3,
MachineID: "3",
MachineName: "m3",
MaxLength: 1050,
},
{
McID: 4,
MachineID: "41",
MachineName: "m4",
MaxLength: 1060,
},
];
const columns = [
{ title: "MachineID", field: "MachineID" },
{ title: "MachineName", field: "MachineName" },
{ title: "MaxLength", field: "MaxLength" },
];
const options = {
layout: "fitColumns",
pagination: "local",
paginationSize: 10,
movableColumns: true,
resizableRows: true,
initialSort: [{ column: "MachineID", dir: "asc" }],
};
return (
<div>
<ReactTabulator
columns={columns}
data={basic_costsheet} // TRY FIVE works as i pass static data or set data directly in useState.
options={options}
/>
{/* Every variable/state/redux state gets printed perfectly so the data is loading (IF AVAILALBE). no issues on that front! */}
<pre>{String(JSON.stringify(basic_costsheet))}</pre>
<pre>{String(JSON.stringify(data))}</pre>
<pre>{String(JSON.stringify(mod_arr))}</pre>
<pre>{String(JSON.stringify(mod_arr_two))}</pre>
<pre>{String(JSON.stringify(cs_data))}</pre>
</div>[![enter image description here][1]][1]
);
};
export default CostSheet;
The issue seems to be that ReactTabulator
is mutating the data
array objects in some way and this breaks when using values directly from a Redux-Toolkit (RTK) created store. This is because RTK uses Immer.js under the hood and enforces that selected state is read-only. In other words, so you don't shoot yourself in the foot by mutating state.
You can simply create new data object references that are not directly coupled to your Store values though. Shallow copy the basic_costsheet
array and shallow copy each array element.
Examples:
const { basic_costsheet } = useSelector((state) => state.qm.costsheet);
...
<ReactTabulator
columns={columns}
data={basic_costsheet.map(item => ({ ...item }))}
options={options}
/>
const basic_costsheet = useSelector((state) => state.qm.costsheet
.basic_costsheet
.map(item => ({ ...item }))
);
...
<ReactTabulator
columns={columns}
data={basic_costsheet}
options={options}
/>