I've put a simple boolean state on a custom header, the plan is the make this state control a dropdown menu. I've used a simple onClick on this custom header that set the states to it's opposite value and after that logs the state. But the state stays the same and doesn't change on each click.
This happens when I set the columns with an initial setState because I need my table to be fully server side based. When setting the columns with a normal let it works but that's not the particular need.
header is highlighted, click on it and you will see the state log in the console.
export default function PositioningActionsColumn() {
const [stateData, setStateData] = useState([]);
const [stateColumns, setStateColumns] = useState([]);
const [isOpen, setIsOpen] = useState(false);
// setting the columns and data - will be from a fetch later
useEffect(() => {
setStateColumns([
{
title: nameHeader,
field: "name"
},
{
title: "Surname",
field: "surname",
initialEditValue: "initial edit value"
},
{ title: "Birth Year", field: "birthYear", type: "numeric" },
{
title: "Birth Place",
field: "birthCity",
lookup: { 34: "İstanbul", 63: "Şanlıurfa" }
}
]);
setStateData([
{ name: "Mehmet", surname: "Baran", birthYear: 1987, birthCity: 63 },
{ name: "Zerya Betül", surname: "Baran", birthYear: 2017, birthCity: 34 }
]);
}, []);
const orderFunc = (orderedColumnId, orderDirection) => {
console.log(
"orderedColumnId:",
orderedColumnId,
"orderDirection:",
orderDirection
);
};
const searchFunc = e => {
console.log(e);
};
const handleClick = () => {
setIsOpen(!isOpen);
console.log(isOpen);
};
const nameHeader = (
<div style={{ background: "lightblue" }} onClick={handleClick}>
Click on this custom Name Header
</div>
);
return (
<MaterialTable
title="Editable Preview"
icons={tableIcons}
columns={stateColumns}
data={stateData}
onOrderChange={(orderedColumnId, orderDirection) => {
orderFunc(orderedColumnId, orderDirection);
}}
onSearchChange={e => searchFunc(e)}
options={{ draggable: false, selection: true, actionsColumnIndex: -1 }}
actions={[
{
tooltip: "Remove All Selected Users",
icon: "delete",
onClick: (evt, data) => {
console.log({ data });
alert("You want to delete " + data.length + " rows");
}
},
{
isFreeAction: true,
tooltip: "FreeAction",
icon: () => <div>Free</div>,
onClick: (evt, data) => {
console.log({ data });
}
}
]}
editable={{
onRowAdd: newData =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
console.log({ newData });
const data = stateData;
data.push(newData);
setStateData(data, () => resolve());
}
resolve();
}, 1000);
}),
onRowUpdate: (newData, oldData) =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
console.log({ newData }, { oldData });
const data = stateData;
const index = data.indexOf(oldData);
data[index] = newData;
setStateData(data, () => resolve());
}
resolve();
}, 1000);
}),
onRowDelete: oldData =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
console.log({ oldData });
let data = stateData;
const index = data.indexOf(oldData);
data.splice(index, 1);
setStateData(data, () => resolve());
}
resolve();
}, 1000);
})
}}
/>
);
}
https://codesandbox.io/s/material-table-testing-actions-position-and-output-2-sj1tt
Change your call of setIsOpen
to:
const handleClick = useCallback(() => setIsOpen(current => !current), []);
It will fix that issue. But still it is not recommended to store react elements in state. It should only contain plain data that you use to render the actual elements.