Update Row Height In MultiRowCellTemplate Throwing flushSync Error

Posted by: matthew.peters on 13 May 2024, 4:28 am EST

    • Post Options:
    • Link

    Posted 13 May 2024, 4:28 am EST

    I am displaying a MultiRow grid that displays 2 rows for each row of data. The first row is to display the data and the second row is to display any messages about the data that were received from the server. Here is the definition:

    <MultiRow ref={gridRef} itemsSource={data}>
        <MultiRowCellGroup>
            <MultiRowCell binding="carNumber" header="Car Number" width={150} isReadOnly={true} />
            <MultiRowCell binding="inboundDate" header="Inbound Date" width={150} cellType="Cell">
                <MultiRowCellTemplate cellType="CellEdit" template=
                    {(context: any) => (
                        <InputDate value={context.value}
                            valueChanged={(inputDate: any) => context.value = inputDate.value} />
                    )} />   
            </MultiRowCell>
            <MultiRowCell binding="shopProcessing" header="Shop Processing" width={150} />
            <MultiRowCell binding="message" header="Feedback Message" colspan={3} isReadOnly={true} allowSorting={false}>
                <MultiRowCellTemplate cellType="Cell" template=
                    {(context: any) => <MessageCellTemplate context={context} gridRef={gridRef} />} />
            </MultiRowCell>
        </MultiRowCellGroup>
    </MultiRow>

    Note the definition of the “Feedback Message” row has a colspan of 3. So for each row of data, the grid will display one row containing the data and a second row displaying a message from the server. However, we only want to show this Feedback Message row IF a message was sent from the server. Otherwise we want to hide it. Here is the MessageCellTemplate code used to show and hide the Feedback Message row:

    const MessageCellTemplate: React.FC<{ context: any, gridRef: any }> = ({ context, gridRef }) => {
    
        if (context.item.message) {
            // We want to show the "Message" line if a message exists
            context.row.height = null;
        } else {
            // Hide the "Message" line if no message exists
            context.row.height = 0
        }
        return context.item.message 
            ?   <span>
                        {context.item.message}
                </span>
            : null;
    }

    The code works on first render of the grid. Our app uses a socket to send and receive updated data from the server. When we get updated data from the server in the socket and modify the data state variable, the grid refreshes. Unfortunately, it also causes the error:

    flushSync was called from inside a lifecycle method. React cannot flush when React is already rendering. Consider moving this call to a scheduler task or micro task

    The Message rows display correctly, we are just getting the error from the MultiRow grid.

    One thing to note: If we comment out the line

    context.row.height = 0

    then the flushSync error does not happen. I have attached a zip file that contains a simple NestJS server to host the socket and a React app that communicates via the socket.

    Steps to replicate the error:

    1 - Start Server

    2 - Start React app. This should connect to the server socket

    3 - Change any data in the grid. Click “Save”

    4 - Data will be sent to the server via the socket and then broadcast back down. Open the browser console to observe error.

    multirow-grid-demo.zip

  • Posted 13 May 2024, 11:51 pm EST

    Hi Matthew,

    Thank you for sharing the working sample. Making changes in the row’s height or visibility of the rows inside the templates may cause such issues. The correct way to hide the unnecessary rows would be by handling the ‘loadedRows’ event of the MultiRow and setting the visible property of the rows as per your needs. Please refer to the following code snippet -

    function loadedRows(s: wjMultirow.MultiRow, e: wjCore.EventArgs) {
            // hides the Feedback rows that doesn't have a message to display
            s.rows.forEach((row: any) => {
                let item = row.dataItem;
                if (row.recordIndex === 1 && !item.message) {
                    row.visible = false;
                } else {
                    row.visible = true;
                }
            })
        }

    Please refer to the updated sample for the same.

    Regards

    multirow-grid-demo-updated.zip

  • Posted 14 May 2024, 12:38 am EST

    This works great for receiving data from the socket. Thank you. I am now getting the flushSync error but in a different place. These are the steps to reproduce:

    1 - Start Server

    2 - Start React app

    3 - Change any of the data for “Car 6”

    4 - Press the button “Change Validation Message Showing”

    5 - flushSync error

  • Posted 15 May 2024, 12:38 am EST

    Hi Matthew,

    It seems replacing the data items with new data items causes this issue internally. To avoid this issue you can use a function to update the current data items in the setData method, instead of replacing it with new items. Please refer to the updated sample for the same.

    The dev is already refactoring the React interop of Wijmo controls, to use the React functional components instead of Class components internally. This issue will be fixed with this change in React Interops of Wijmo controls. And most probably, it will be added in the next stable release of Wijmo. For now, you can follow the approach mentioned above.

    Regards

    multirow-grid-demo-updated.zip

  • Posted 16 May 2024, 11:37 pm EST

    Thank you so much for your answers. They were very helpful.

    One note, though. In your code you mention this property:

    row.recordIndex

    That is a VERY helpful property and accelerated our dev time. Unfortunately, it is not in your documentation for the Row class:

    https://developer.mescius.com/wijmo/api/classes/Wijmo_Grid.Row.html

    I did a Google search on the property and only found this jsFiddle which also talks about dataIndex:

    https://jsfiddle.net/Wijmo5/6kqzfc39/

    I highly recommend updating your documentation to include this property.

  • Posted 19 May 2024, 7:46 pm EST

    Hi Matthew,

    The ‘recordIndex’ property is not available on the ‘Row’ class, it is available on the ‘_MultiRow’ class (extended from the Row class). And ‘_MultiRow’ is an internal class created for internal use only, so this class information is not mentioned in our documentation, hence the ‘recordIndex’ property is also not available in the documentation. However, you can use this property as per your requirements, if needed.

    We have created a request to update the documentation with the internal tracking ID - WJM-33944. We will let you know when the documentation is updated.

    Regards

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels