Columns order keeps reseting when react-router navigating with persistence

Hello,

I have persistent grid that is working correctly with browser refresh and navigation. Persistent state is saved when navigating away, but it resets when navigating on the page with this grid.

dataSource is empty array at start and then it fills with data. This problem is not caused by metadata columns. Sometimes it seems that columns order is correct on first render and than it resets.

I'll provide more information if needed — I just wasn't sure what else would be relevant to include at this point.

SyncFusion version: 29.1.37



{!loading && (
                <Collapse in={expanded}>
                    <GridComponent
                        clipMode="EllipsisWithTooltip"
                        ref={gridRef}
                        name="todo-list"
                        id={gridId}
                        dataSource={dataSource}
                        height={height}
                        enablePersistence
                        allowFiltering
                        allowSorting
                        allowResizing
                        allowReordering
                        showColumnChooser
                        locale={sfLanguage()}
                        filterSettings={{ type: 'Excel', ignoreAccent: true }}
                        selectionSettings={{ mode: 'Row', type: 'Multiple' }}
                        pageSettings={{ pageSize: 10 }}
                        queryCellInfo={(e: any) => {
                            if (!e.column) return;
                            if (!e.cell) return;
                            if (!e.data.deadline) return;
                            const { field } = e.column;
                            const pastDeadline = moment().isSameOrAfter(e.data.deadline);

                            if ((field === 'title' && pastDeadline) || (field === 'deadline' && pastDeadline)) {
                                e.cell.style.color = 'red';
                            }
                        }}
                        recordDoubleClick={(e: RecordDoubleClickEventArgs) => {
                            const rowData = e.rowData as ToDoDTO;

                            handleRedirectToTask(rowData.id);
                        }}
                        actionBegin={(args) => {
                            handleActionBegin(args);
                        }}
                    >
                        <ColumnsDirective>
                            <ColumnDirective
                                field="id"
                                headerText={t('ID')}
                                isPrimaryKey
                                valueAccessor={(_, data) => {
                                    const rowData = data as ToDoDTO;

                                    return `#${rowData.id}`;
                                }}
                            />
                            <ColumnDirective
                                field="title"
                                headerText={t('Název')}
                                css={{ color: 'red' }}
                            />
                            <ColumnDirective
                                field="typ"
                                headerText={t('Typ')}
                            />
                            <ColumnDirective
                                field="deadline"
                                headerText={t('Deadline')}
                                type="date"
                                format={dateFormat}
                            />
                            <ColumnDirective
                                field="stavDatum"
                                headerText={t('Poslední změna stavu')}
                                type="datetime"
                                format={dateTimeFormat}
                            />
                            <ColumnDirective
                                field="stav"
                                headerText={t('Stav')}
                            />
                            <ColumnDirective
                                field="priority"
                                headerText={t('Priorita')}
                            />
                            <ColumnDirective
                                field="assigneesResponsible"
                                headerText={t('Odpovědnost')}
                            />
                            <ColumnDirective
                                field="entityNazev"
                                headerText={t('Element')}
                            />
                            <ColumnDirective
                                field="autor"
                                headerText={t('Autor')}
                            />
                            <ColumnDirective
                                field="tags"
                                headerText={t('Štítky')}
                                template={tagsTemplate}
                            />

                            {metadataTypes &&
                                metadataTypes.length > 0 &&
                                metadataTypes.map((metadataType) => (
                                    <ColumnDirective
                                        key={metadataType?.id.toString()}
                                        field={metadataType?.id.toString()}
                                        headerText={metadataType?.nazev}
                                        type={getMetadataGridType(metadataType?.datovyTyp)}
                                        displayAsCheckBox={metadataType?.datovyTyp === TYP_METADATA.BOOLEAN}
                                    />
                                ))}

                            <ColumnDirective
                                template={bcfTemplate}
                                showColumnMenu={false}
                                showInColumnChooser={false}
                                index={990}
                            />
                            <ColumnDirective
                                template={processTaskTemplate}
                                showColumnMenu={false}
                                showInColumnChooser={false}
                                index={991}
                            />
                            <ColumnDirective
                                headerText=""
                                field="isLocked"
                                template={lockedTemplate}
                                showColumnMenu={false}
                                showInColumnChooser={false}
                                index={992}
                            />

                            <ColumnDirective
                                template={deleteTemplate}
                                showColumnMenu={false}
                                showInColumnChooser={false}
                                index={993}
                            />
                        </ColumnsDirective>
                        <Inject services={[Sort, Filter, Resize, Reorder, ColumnChooser]} />
                    </GridComponent>
                </Collapse>
            )}




Attachment: grid_sorting_a9ef4a4b.png


6 Replies

DM Dineshnarasimman Muthu Syncfusion Team April 17, 2025 03:13 AM UTC

Hi,


We have reviewed your query regarding the persistence not properly working in the grid. It seems that you are using routing in the application and on navigating to other page and coming back to grid, it doesn't persist the grid properties. Based on the provided code information, we have prepared a simple routing sample along similar implementation, we cannot able to replicate the issue from our end, the persistence seems to be working properly from our end.


We have attached the sample and video demonstration for your reference.


We have also attached the documentation on persisting the template columns in the grid where it is explained in detail.


Documentation: https://helpej2.syncfusion.com/react/documentation/grid/state-management#persist-the-column-template-header-template-and-header-text



We request you to provide the following information to validate it further.


  • The persistence relies on the Grid’s unique id, so please ensure that the “gridId” is not updated dynamically.
  • Please ensure whether the issue replicates in the provided sample, if not please replicate the issue by modifying the sample.


  • Ensure us whether you have set any culture or localization in your application.


  • Please provide the video demonstration, which will help us to identify the replication procedure and the issue you are facing.


Please get back to us for further assistance.


Regards,

Dineshnarasimman M



Attachment: GridPersistence_3dc25028.zip


DM Dineshnarasimman Muthu Syncfusion Team April 17, 2025 03:16 AM UTC

Hi,


Please find the below attached sample for your reference.


Regards,
Dineshnarasimman M

Attachment: GridPersistence_b9d190b1.zip


MM Miloš Musílek April 22, 2025 11:50 AM UTC

Hello,

id is unique and static. Localization is "cs-CZ".

I was able to replicate my problem with changing data with useEffect, setTimeout, and useState. I attached video and modified sample project.

BR,

Milos


Attachment: ReactRouting_31359bc2.zip


DM Dineshnarasimman Muthu Syncfusion Team April 23, 2025 09:22 AM UTC

Hi,


We observed that you're dynamically updating the dataSource and metaColumn state values inside the useEffect of the component. Dynamically setting metadataTypes in useEffect, and then rendering the corresponding ColumnDirective components based on that state, may cause issues in the Syncfusion Grid.


We recommend rendering the Grid component only after the state values have been set during the initial useEffect execution.


Please refer to the attached code snippet and sample for your reference. 


 

  React.useEffect(() => {

    // Simulate fetching data from an API

    setTimeout(() => {

      setSampleData(sampleDataStatic);

      setMetadataTypes(metadataTypesStatic);

    });

  }, []);

 

 

return (sampleData.length > 0 && metadataTypes.length > 0 ? (

    <GridComponent

      clipMode="EllipsisWithTooltip"

      ref={gridRef}

      name="todo-list"

      id={gridId}

      dataSource={sampleData}

      height={400}

      enablePersistence

.

.

.     

 

    >

      <ColumnsDirective>

        <ColumnDirective

          field="id"

          headerText={t("ID")}

          isPrimaryKey

          valueAccessor={(_, data) => `#${data.id}`}

        />

        <ColumnDirective field="title" headerText={t("Název")} />

        <ColumnDirective field="typ" headerText={t("Typ")} />

        <ColumnDirective

          field="deadline"

          headerText={t("Deadline")}

          type="date"

          format={dateFormat}

        />

        <ColumnDirective

          field="stavDatum"

          headerText={t("Poslední změna stavu")}

          type="datetime"

          format={dateTimeFormat}

        />

        {metadataTypes.map((metadataType) => (

          <ColumnDirective

            key={metadataType.id}

            field={metadataType.id.toString()}

            headerText={metadataType.nazev}

            type={getMetadataGridType(metadataType.datovyTyp)}

            displayAsCheckBox={metadataType.datovyTyp === "BOOLEAN"}

          />

        ))}

      </ColumnsDirective>

      <Inject services={[Sort, Filter, Resize, Reorder, ColumnChooser]} />

    </GridComponent>

  ) : null);

 


Please find the video demonstration and the sample for your reference. Please get back to us for further assistance.


Regards,

Dineshnarasimman M


Attachment: ReactRoutingPersistence_5fbfd03f.zip


MM Miloš Musílek April 23, 2025 10:24 AM UTC

Hello,


in the meantime we fixed it by manually loading state after data change. This works for us.


Thank you for your time, I learned new tricks.


BR,

Milos M.



DM Dineshnarasimman Muthu Syncfusion Team April 24, 2025 06:46 AM UTC

Hi,

 

We are glad that the issue has been resolved. Please get back to us for further assistance.

 

Regards,

Dineshnarasimman M


Loader.
Up arrow icon