Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tree view] onBlur event causes TreeView performance issues #11518

Open
bigrivi opened this issue Dec 26, 2023 · 0 comments · May be fixed by #11558
Open

[tree view] onBlur event causes TreeView performance issues #11518

bigrivi opened this issue Dec 26, 2023 · 0 comments · May be fixed by #11558
Labels
component: tree view TreeView, TreeItem. This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature

Comments

@bigrivi
Copy link

bigrivi commented Dec 26, 2023

Steps to reproduce

If the TreeItem contains a text input box, it will cause a lot of unnecessary re-rendering.

The useTreeViewFocus.ts file contains settings for monitoring the focus and blur events of the main container. When the focus and blur events occur, the focusedNodeId status change will be set. Once there are a large number of form elements in the treeitem, the entire tree will be frequently re-rendered.
`

import * as React from "react";
import useEventCallback from "@mui/utils/useEventCallback";
import { EventHandlers } from "@mui/base/utils";
import ownerDocument from "@mui/utils/ownerDocument";
import { TreeViewPlugin } from "../../models";
import { populateInstance } from "../../useTreeView/useTreeView.utils";
import { UseTreeViewFocusSignature } from "./useTreeViewFocus.types";
import { useInstanceEventHandler } from "../../hooks/useInstanceEventHandler";

export const useTreeViewFocus: TreeViewPlugin<UseTreeViewFocusSignature> = ({
    instance,
    params,
    state,
    setState,
    models,
    rootRef,
}) => {
    const setFocusedNodeId = useEventCallback(
        (nodeId: React.SetStateAction<string | null>) => {
            const cleanNodeId =
                typeof nodeId === "function"
                    ? nodeId(state.focusedNodeId)
                    : nodeId;
            console.log("try set focusId", cleanNodeId);
            setState((prevState) => ({
                ...prevState,
                focusedNodeId: cleanNodeId,
            }));
        }
    );

    const isNodeFocused = React.useCallback(
        (nodeId: string) => state.focusedNodeId === nodeId,
        [state.focusedNodeId]
    );

    const focusNode = useEventCallback(
        (event: React.SyntheticEvent, nodeId: string | null) => {
            if (nodeId) {
                setFocusedNodeId(nodeId);
                console.log("call focusNode");
                if (params.onNodeFocus) {
                    params.onNodeFocus(event, nodeId);
                }
            }
        }
    );

    populateInstance<UseTreeViewFocusSignature>(instance, {
        isNodeFocused,
        focusNode,
    });

    useInstanceEventHandler(instance as any, "removeNode", ({ id }) => {
        setFocusedNodeId((oldFocusedNodeId) => {
            if (
                oldFocusedNodeId === id &&
                rootRef.current === ownerDocument(rootRef.current).activeElement
            ) {
                return instance.getChildrenIds(null)[0];
            }
            return oldFocusedNodeId;
        });
    });

    const createHandleFocus =
        (otherHandlers: EventHandlers) =>
        (event: React.FocusEvent<HTMLUListElement>) => {
            otherHandlers.onFocus?.(event);

            // if the event bubbled (which is React specific) we don't want to steal focus
            if (event.target === event.currentTarget) {
                const isNodeVisible = (nodeId: string) => {
                    const node = instance.getNode(nodeId);
                    return (
                        node &&
                        (node.parentId == null ||
                            instance.isNodeExpanded(node.parentId))
                    );
                };

                let nodeToFocusId: string | null | undefined;
                if (Array.isArray(models.selected.value)) {
                    nodeToFocusId = models.selected.value.find(isNodeVisible);
                } else if (
                    models.selected.value != null &&
                    isNodeVisible(models.selected.value)
                ) {
                    nodeToFocusId = models.selected.value;
                }

                if (nodeToFocusId == null) {
                    nodeToFocusId = instance.getNavigableChildrenIds(null)[0];
                }
                console.log(instance);
                instance.focusNode(event, nodeToFocusId);
            }
        };

    const createHandleBlur =
        (otherHandlers: EventHandlers) =>
        (event: React.FocusEvent<HTMLUListElement>) => {
            otherHandlers.onBlur?.(event);
            console.log("blur", event.currentTarget);
            console.log(event.target);
            setFocusedNodeId(null);
        };

    const focusedNode = instance.getNode(state.focusedNodeId!);
    const activeDescendant = focusedNode ? focusedNode.idAttribute : null;

    return {
        getRootProps: (otherHandlers) => ({
            onFocus: createHandleFocus(otherHandlers),
            onBlur: createHandleBlur(otherHandlers),
            "aria-activedescendant": activeDescendant ?? undefined,
        }),
    };
};

useTreeViewFocus.getInitialState = () => ({ focusedNodeId: null });

useTreeViewFocus.getDefaultizedParams = (params) => ({
    ...params,
    disabledItemsFocusable: params.disabledItemsFocusable ?? false,
});
`
Everyone, is there any way to actively turn off the focus and blur events? In order to improve performance, I can accept the expectation of not responding to the focus effect.




### Current behavior

_No response_

### Expected behavior

_No response_

### Context

_No response_

### Your environment

<details>
  <summary><code>npx @mui/envinfo</code></summary>

Don't forget to mention which browser you used.
Output from npx @mui/envinfo goes here.

</details>



**Search keywords**: performance
@bigrivi bigrivi added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Dec 26, 2023
@zannager zannager added the component: tree view TreeView, TreeItem. This is the name of the generic UI component, not the React module! label Dec 26, 2023
@flaviendelangle flaviendelangle added enhancement This is not a bug, nor a new feature and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jan 3, 2024
@flaviendelangle flaviendelangle changed the title onBlur event causes TreeView performance issues [tree view] onBlur event causes TreeView performance issues Jan 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: tree view TreeView, TreeItem. This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants