Infinte Loop on afterSetCellMeta

Tags: #<Tag:0x00007f51b9209b50> #<Tag:0x00007f51b9209a10>

i am using version 14
i have a state in react
const [cellMeta, setCellMeta] = useState([]);
on afterSetCellMeta i call a function to insert the meta for the cells and i pass the state to handsontable cell

cell={
                rows.length && columns.length 
                ? cellMeta
                : undefined
            }

on doing so an infinte loop starts and i am not able to get the reason why,

Hi @guneetsinghtuli

Thank you for contacting us. Can you please share a code demo where the issue is replicable? It will be easier to debug it this way.

Hey @adrian.szymanski

You can find the code sandbox here https://codesandbox.io/p/devbox/p32xrg
I have added a comment on line 95

In order to replicate

  1. Open Console
  2. Click on any header and align it to any direction
  3. You will find a infinite loop which will eventually crash the application
  4. You can comment the line 95 cell={cellMeta} and perform the same in order to see the expected behaviour (it should trigger the function update the state and cell should acknowledge the updated state)

and Please let me know if I am missing on something with this

Hi @guneetsinghtuli

Thank you for the example. I checked it and followed your instructions but I don’t get any errors and sorting works fine. Can you please recheck it?

Hey @adrian.szymanski

You can have look at this screen recording

@guneetsinghtuli

Thank you for the recording. Now I am able to reproduce the issue. I think the reason for the error is explained quite well in the message itself:

Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn’t have a dependency array, or one of the dependencies changes on every render.

So, basically, there are too many updates within the logic you created and the results in an infinite loop.

Hey @adrian.szymanski

Currently in the code base I am only using useEffect to log the updates I can replicate the issue by removing that as well

So I am not sure if it’s the problem with my code logic or an actual issue with handsontable

  useEffect(() => {
    console.log("cellMeta", cellMeta);
  }, [cellMeta]);

@guneetsinghtuli

Maybe let’s change the approach here. Can you please tell me what is your expected result with the logic you have?

@adrian.szymanski

We have a case where the alignment or any css changes to any cell must persist but in order to persist we don’t use any local storage or session since for now we are using a react state

You can just assume it as a normal react state which will persist on reload, So whenever we make any changes to the alignment or any cell level change mostly css.
I saved the changes in a state and then pass it back to the handsontable so on reload as well you fill find the same alignment and css

I can’t use the default handsontable persistence state as I am in a restricted environment of iframe without access to local storage or any other

Hi @guneetsinghtuli

Thank you for the explanation. I did some more research and the reason for the loop is most likely due the fact that you are reading from the state in both cell option and afterSetCellData hook. Both of them will trigger re-rendering of the whole table and that will cause the infinite loop. In this case I would suggest to keep the logic and reading from state only to one of those methods.

Hey @adrian.szymanski

I do agree that can a possible explanation for infinite while loop, For My use case In order to save the UI change which user made like alignment or something I can apply the afterSetCellData hook and save it, But how can I apply the styling back later on after a reload if I can’t use the cell option is there any other parameter which I can use to pass back the last state of styling ?

@guneetsinghtuli

I’ll check the available options and update you after the weekend.

The reason you are encountering an infinite loop is because you are attempting to set the cell meta in the afterSetCellData hook. Unfortunately, I couldn’t get setState to work in useEffect. The only way I could get it to work was using a plain JS Map. Does this work for you:

https://codesandbox.io/p/devbox/handsontable-forked-9z845z

Hi @timeflys54321

Thank you for the suggestion. Let’s wait for @guneetsinghtuli confirmation if that helps.

Hey @adrian.szymanski @timeflys54321

Thank you for this suggestion I will try to implement it on my use case and let you know by tomorrow.

Hi @guneetsinghtuli

Is this subject can be closed? If you’d need anything more that what was suggested please let us know.

Hi, I am Dhairya, I work with Guneet.

This is the same code as the solution you posted: https://codesandbox.io/p/devbox/handsontable-forked-9z845z.

The only change I made is adding a log inside afterSetCellMeta to track updates to cellMeta. However, I noticed that when I log the Map, it still shows the previous state instead of reflecting the latest update.

Here’s my implementation:

const cellMeta: Map<
  string,
  {
row: number;
col: number;
[key: string]: any;
  }
> = new Map();

const afterSetCellMeta = (row, col, key, value) => {
  const mapKey = `${row},${col}`;
  const metaRow = cellMeta.get(mapKey);

  if (metaRow) {
cellMeta.set(mapKey, { [key]: value, ...metaRow });
  } else {
cellMeta.set(mapKey, { row, col, [key]: value });
  }

  console.log("Updated cell meta:", cellMeta);
};

code sanbox link of my implementation: https://codesandbox.io/p/devbox/handsontable-forked-mqjjpg?file=%2Fapp%2Fpage.tsx%3A30%2C36

The issue is that cellMeta doesn’t reflect the latest state when logged inside afterSetCellMeta. Instead, it always shows the previous state. It seems like the Map isn’t updating immediately.

Can you suggest a way to get the updated state correctly?
Below is the screen shot to help you identify the issue better.

Hi @dhairyasehgal2307

Thank you for sharing the demo. It uses no theme. Meaning all elements like arrows (for sorting, dropdown or date), checkboxes, cell classes are not applied. I recommend using Classic theme (the one that was used before v15.0.0 or any of our new themes Main or Horizon. Plus CodeSandbox itself has sometimes issue with integrating Handsontable modules. We used it before but now we moved to Stackblitz. Could you please check what is missing in this demo https://stackblitz.com/edit/react-g3xcx4uf-aa6tkdae?file=src%2FExampleComponent.jsx,src%2Fdata.js?

@dhairyasehgal2307, I made a mistake with the order when constructing the meta object.
It should be:

cellMeta.set(mapKey, { ...metaRow, [key]: value });
instead of
cellMeta.set(mapKey, { [key]: value, ...metaRow });

I’ve updated the fork to reflect that.