fix: remove unnecessary re-renders on JS Object context menu in explorer (#14866)

* Fixes rerenders on JS context menu

* Fixed warnings

* Fix review comments

* Perf adjustments

* Replace entityName hook with a function that reads from store.

* Use menuOptions selectors to populate options
This commit is contained in:
arunvjn 2022-07-07 11:08:05 +05:30 committed by GitHub
parent 1ca40f9eeb
commit bed2a02fdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 53 deletions

View File

@ -1,7 +1,6 @@
import React, { useCallback, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import TreeDropdown from "pages/Editor/Explorer/TreeDropdown";
import { AppState } from "reducers";
import ContextMenuTrigger from "../ContextMenuTrigger";
import {
moveJSCollectionRequest,
@ -9,8 +8,8 @@ import {
deleteJSCollection,
} from "actions/jsActionActions";
import { ContextMenuPopoverModifiers } from "../helpers";
import { noop } from "lodash";
import { useNewJSCollectionName } from "./helpers";
import noop from "lodash/noop";
import { getJSEntityName } from "./helpers";
import { initExplorerEntityNameEdit } from "actions/explorerActions";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
@ -24,6 +23,7 @@ import {
CONTEXT_SHOW_BINDING,
createMessage,
} from "@appsmith/constants/messages";
import { getPageListAsOptions } from "selectors/entitiesSelector";
type EntityContextMenuProps = {
id: string;
@ -32,9 +32,7 @@ type EntityContextMenuProps = {
pageId: string;
};
export function JSCollectionEntityContextMenu(props: EntityContextMenuProps) {
const nextEntityName = useNewJSCollectionName();
const [confirmDelete, setConfirmDelete] = useState(false);
const dispatch = useDispatch();
const showBinding = useCallback(
@ -52,26 +50,30 @@ export function JSCollectionEntityContextMenu(props: EntityContextMenuProps) {
);
const copyJSCollectionToPage = useCallback(
(actionId: string, actionName: string, pageId: string) =>
(actionId: string, actionName: string, pageId: string) => {
const nextEntityName = getJSEntityName();
dispatch(
copyJSCollectionRequest({
id: actionId,
destinationPageId: pageId,
name: nextEntityName(actionName, pageId, true),
}),
),
[dispatch, nextEntityName],
);
},
[dispatch],
);
const moveJSCollectionToPage = useCallback(
(actionId: string, actionName: string, destinationPageId: string) =>
(actionId: string, actionName: string, destinationPageId: string) => {
const nextEntityName = getJSEntityName();
dispatch(
moveJSCollectionRequest({
id: actionId,
destinationPageId,
name: nextEntityName(actionName, destinationPageId, false),
}),
),
[dispatch, nextEntityName, props.pageId],
);
},
[dispatch, props.pageId],
);
const deleteJSCollectionFromPage = useCallback(
(actionId: string, actionName: string) =>
@ -79,13 +81,7 @@ export function JSCollectionEntityContextMenu(props: EntityContextMenuProps) {
[dispatch],
);
const menuPages = useSelector((state: AppState) => {
return state.entities.pageList.pages.map((page) => ({
label: page.pageName,
id: page.pageId,
value: page.pageName,
}));
});
const menuPages = useSelector(getPageListAsOptions);
const editJSCollectionName = useCallback(
() => dispatch(initExplorerEntityNameEdit(props.id)),
[dispatch, props.id],

View File

@ -1,18 +1,14 @@
import React, { useCallback, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { AppState } from "reducers";
import {
moveJSCollectionRequest,
copyJSCollectionRequest,
deleteJSCollection,
} from "actions/jsActionActions";
import { ContextMenuPopoverModifiers } from "../helpers";
import { noop } from "lodash";
import noop from "lodash/noop";
import TreeDropdown from "pages/Editor/Explorer/TreeDropdown";
import { useNewJSCollectionName } from "./helpers";
import { getJSEntityName } from "./helpers";
import styled from "styled-components";
import Icon, { IconSize } from "components/ads/Icon";
import { Position } from "@blueprintjs/core";
@ -23,6 +19,7 @@ import {
CONTEXT_MOVE,
createMessage,
} from "@appsmith/constants/messages";
import { getPageListAsOptions } from "selectors/entitiesSelector";
type EntityContextMenuProps = {
id: string;
@ -70,31 +67,35 @@ export const MoreActionablesContainer = styled.div<{ isOpen?: boolean }>`
export function MoreJSCollectionsMenu(props: EntityContextMenuProps) {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const nextEntityName = useNewJSCollectionName();
const [confirmDelete, setConfirmDelete] = useState(false);
const dispatch = useDispatch();
const copyJSCollectionToPage = useCallback(
(actionId: string, actionName: string, pageId: string) =>
(actionId: string, actionName: string, pageId: string) => {
const nextEntityName = getJSEntityName();
dispatch(
copyJSCollectionRequest({
id: actionId,
destinationPageId: pageId,
name: nextEntityName(`${actionName}Copy`, pageId),
}),
),
[dispatch, nextEntityName],
);
},
[dispatch],
);
const moveJSCollectionToPage = useCallback(
(actionId: string, actionName: string, destinationPageId: string) =>
(actionId: string, actionName: string, destinationPageId: string) => {
const nextEntityName = getJSEntityName();
dispatch(
moveJSCollectionRequest({
id: actionId,
destinationPageId,
name: nextEntityName(actionName, destinationPageId, false),
}),
),
[dispatch, nextEntityName, props.pageId],
);
},
[dispatch],
);
const deleteJSCollectionFromPage = useCallback(
(actionId: string, actionName: string) =>
@ -102,13 +103,7 @@ export function MoreJSCollectionsMenu(props: EntityContextMenuProps) {
[dispatch],
);
const menuPages = useSelector((state: AppState) => {
return state.entities.pageList.pages.map((page) => ({
label: page.pageName,
id: page.pageId,
value: page.pageName,
}));
});
const menuPages = useSelector(getPageListAsOptions);
return (
<TreeDropdown

View File

@ -1,26 +1,22 @@
import { useMemo } from "react";
import { useSelector } from "react-redux";
import { AppState } from "reducers";
import { getNextEntityName } from "utils/AppsmithUtils";
import { groupBy } from "lodash";
import { JSCollectionData } from "reducers/entityReducers/jsActionsReducer";
import { selectJSCollections } from "selectors/editorSelectors";
import store from "store";
export const useNewJSCollectionName = () => {
const jsactions = useSelector((state: AppState) => state.entities.jsActions);
const groupedActions = useMemo(() => {
return groupBy(jsactions, "config.pageId");
}, [jsactions]);
export const getJSEntityName = () => {
const state = store.getState();
const jsCollections = selectJSCollections(state);
return (
name: string,
destinationPageId: string,
isCopyOperation?: boolean,
) => {
const pageActions = groupedActions[destinationPageId];
// Get action names of the destination page only
const actionNames = pageActions
? pageActions.map((action: JSCollectionData) => action.config.name)
: [];
const groupedActions = groupBy(jsCollections, "config.pageId");
const pageActions = groupedActions[destinationPageId] || [];
const actionNames = pageActions.map(
(action: JSCollectionData) => action.config.name,
);
return actionNames.indexOf(name) > -1
? getNextEntityName(
isCopyOperation ? `${name}Copy` : name,

View File

@ -532,3 +532,6 @@ export const getEditorURL = createSelector(
pageId,
}),
);
export const selectJSCollections = (state: AppState) =>
state.entities.jsActions;