Kendo Grid column unmounts/mounts child component on re-render

6 posts, 0 answers
  1. Grid Trekkor
    Grid Trekkor avatar
    2 posts
    Member since:
    May 2017

    Posted 10 Oct 2019 Link to this post

    Hi,

    One of my grid columns uses a child component to display its own data for each row in the grid.  I have a demo here:

    https://stackblitz.com/edit/react-mu6rlr?file=app/main.jsx

    The issue is that any state change in the parent causes that child in the grid column to unmount re-mount.  Try opening the console at the bottom right.  Then type any text in the input.  You can see that for each state change, the child unmounts and re-mounts.

    In my real app, the child is fetching data with axios.  So for each keystroke (or ANY state change), that child unmounts, remounts, and fetches the data again.  This also happens with any action on the grid, such as sorting.  Sort the grid, and the child unmounts and remounts.

    How can I prevent this behavior?  I can't have the child re-fetching the data like that.

    Thanks for any help.

  2. Stefan
    Admin
    Stefan avatar
    3039 posts

    Posted 11 Oct 2019 Link to this post

    Hello, Grid,

    Thank you for the example.

    This occurs because a new function is made inside render each time the state is changed.

    This can be resolved by utilizing the useMemo hook which will memorize the cell and not re-mount it every time:

    https://stackblitz.com/edit/react-mu6rlr-cc837t?file=app/main.jsx

    Also, if the props from the parent component have to be passed to the custom cell, we recommend using the new context API. This is an example with context:

    https://stackblitz.com/edit/react-mu6rlr-ei1u9a?file=app/main.jsx

    I hope one of this approaches proves helpful.

    Regards,
    Stefan
    Progress Telerik

    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. Grid Trekkor
    Grid Trekkor avatar
    2 posts
    Member since:
    May 2017

    Posted 11 Oct 2019 in reply to Stefan Link to this post

    Hi Stefan, thank you for the explanation and demo.  Much appreciated.
  4. Kyle
    Kyle avatar
    2 posts
    Member since:
    Nov 2019

    Posted 09 Oct 2020 Link to this post

    For all those wondering how to stop the re-render "unfocusing" in other kendo components that you are making controlled components (see Forms, Conversational UI, etc) useMemo worked!

     

    Here is an example (@stefan you might want to add this to the docs for Forms and Conversational UI under the "controlled section" to help out future devs) -- this also solves the "multi line message box" but you have to wire up the send button action yourself.

    ```
    import React, { SyntheticEvent, useMemo, useState } from 'react';
    import { Button } from '@progress/kendo-react-buttons';
    import { Chat, ChatMessageBoxProps } from '@progress/kendo-react-conversational-ui';
    import { Editor } from '@progress/kendo-react-editor';
    import { useDebouncedCallback } from 'use-debounce/lib';
    import { getRawText } from '../../util/HtmlToText';

    export interface MessageBoxProps extends ChatMessageBoxProps {
    onChange: Function;
    onSend: Function;
    value?: string;
    }
    const MessageBox = ({ onSend, toolbarButton, onChange, value }: MessageBoxProps) => {
    // Debounce callback
    const [debouncedCallback] = useDebouncedCallback(onChange, 500); // helps reduce re-renders
    return (
    <>
    {toolbarButton}
    <Editor
    defaultEditMode="div"
    style={{ width: 'calc(100% - 100px)' }}
    contentStyle={{ width: '100%' }}
    onChange={e => debouncedCallback(getRawText(e.html))}
    defaultContent={value}
    />
    <Button onClick={onSend}>
    Send
    </Button>
    </>
    );
    }
    export type ChatWithEditorProps = {
    onChange: (values: { [name: string]: any; }, event?: SyntheticEvent<any, Event> | undefined) => void;
    data: any;
    messages: any[];
    };

    const ChatWithEditor = ({ onChange, data, messages }: ChatWithEditorProps) => {
    const [showToolbar, setShowToolbar] = useState(false);
    const messageBox = useMemo(
    () => (props: any) => <MessageBox {...props} onChange={text => onChange({ ...data, text })} value={data.text} />,
    []
    );
    return (
    <Chat
    width="100%"
    user={{ id: data.from }}
    messages={messages}
    onToolbarActionExecute={() => setShowToolbar(!showToolbar)}
    showToolbar={showToolbar}
    placeholder="Send a message"
    toolbar={
    <span>
    <Button icon="image" look="outline" onClick={() => console.log('toolbar btn clicked')} />
    </span>
    }
    messageBox={messageBox}
    />
    );
    };
    export default ChatWithEditor;
    ```

  5. Kyle
    Kyle avatar
    2 posts
    Member since:
    Nov 2019

    Posted 09 Oct 2020 in reply to Kyle Link to this post

    we lost all formatting on that paste, here is a stackblitz 

    https://stackblitz.com/edit/react-mu6rlr-b3a9vn?file=app%2Fmain.tsx

     

    it doesn't "work" in stack blitz, only there for formatting purposes so you can see what I did. (all in typescript, that's why it didn't work ootb in stackblitz, but I didn't spend the time to fix it)

  6. Stefan
    Admin
    Stefan avatar
    3039 posts

    Posted 12 Oct 2020 Link to this post

    Hello, Kyle,

    Thank you very much for sharing the example, it is highly appreciated.

    I have also added some Telerik points to your account for sharing this with the KendoReact community.

    Regards,
    Stefan
    Progress Telerik

    Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Back to Top