performance improvements & refactor

This commit is contained in:
AykutSarac 2022-09-09 11:58:18 +03:00
parent 3d3de397c4
commit 7f8bd9d1f7
8 changed files with 150 additions and 143 deletions

View File

@ -6,12 +6,9 @@ import {
} from "react-zoom-pan-pinch";
import { Canvas, Edge, ElkRoot } from "reaflow";
import { CustomNode } from "src/components/CustomNode";
import { NodeModal } from "src/containers/Modals/NodeModal";
import useConfig from "src/hooks/store/useConfig";
import styled from "styled-components";
import shallow from "zustand/shallow";
import useGraph from "src/hooks/store/useGraph";
import { parser } from "src/utils/jsonParser";
import styled from "styled-components";
interface LayoutProps {
isWidget: boolean;
@ -41,27 +38,21 @@ const StyledEditorWrapper = styled.div<{ isWidget: boolean }>`
}
`;
const MemoizedGraph = React.memo(function Layout({
export const Graph = ({
isWidget,
openModal,
setSelectedNode,
}: LayoutProps) {
const json = useConfig((state) => state.json);
}: LayoutProps) => {
const setConfig = useConfig((state) => state.setConfig);
const layout = useConfig((state) => state.layout);
const nodes = useGraph((state) => state.nodes);
const edges = useGraph((state) => state.edges);
const setGraphValue = useGraph((state) => state.setGraphValue);
const [size, setSize] = React.useState({
width: 2000,
height: 2000,
});
const [expand, layout] = useConfig(
(state) => [state.expand, state.layout],
shallow
);
const handleNodeClick = React.useCallback(
(e: React.MouseEvent<SVGElement>, data: NodeData) => {
setSelectedNode(data.text);
@ -88,13 +79,6 @@ const MemoizedGraph = React.memo(function Layout({
if (input) input.blur();
}, []);
React.useEffect(() => {
const { nodes, edges } = parser(json, expand);
setGraphValue("nodes", nodes);
setGraphValue("edges", edges);
}, [expand, json, setGraphValue]);
return (
<StyledEditorWrapper isWidget={isWidget}>
<TransformWrapper
@ -145,49 +129,4 @@ const MemoizedGraph = React.memo(function Layout({
</TransformWrapper>
</StyledEditorWrapper>
);
});
export const Graph = ({ isWidget = false }: { isWidget?: boolean }) => {
const [isModalVisible, setModalVisible] = React.useState(false);
const [selectedNode, setSelectedNode] = React.useState<[string, string][]>(
[]
);
const openModal = React.useCallback(() => setModalVisible(true), []);
const collapsedNodes = useGraph((state) => state.collapsedNodes);
const collapsedEdges = useGraph((state) => state.collapsedEdges);
React.useEffect(() => {
const nodeList = collapsedNodes.map((id) => `[id$="node-${id}"]`);
const edgeList = collapsedEdges.map((id) => `[class$="edge-${id}"]`);
const hiddenItems = document.querySelectorAll(".hide");
hiddenItems.forEach((item) => item.classList.remove("hide"));
if (nodeList.length) {
const selectedNodes = document.querySelectorAll(nodeList.join(","));
const selectedEdges = document.querySelectorAll(edgeList.join(","));
selectedNodes.forEach((node) => node.classList.add("hide"));
selectedEdges.forEach((edge) => edge.classList.add("hide"));
}
}, [collapsedNodes, collapsedEdges]);
return (
<>
<MemoizedGraph
openModal={openModal}
setSelectedNode={setSelectedNode}
isWidget={isWidget}
/>
{!isWidget && (
<NodeModal
selectedNode={selectedNode}
visible={isModalVisible}
closeModal={() => setModalVisible(false)}
/>
)}
</>
);
};

View File

@ -0,0 +1,85 @@
import React from "react";
import styled from "styled-components";
import Editor, { loader } from "@monaco-editor/react";
import { Loading } from "src/components/Loading";
import { parser } from "src/utils/jsonParser";
import useConfig from "src/hooks/store/useConfig";
import useStored from "src/hooks/store/useStored";
import useGraph from "src/hooks/store/useGraph";
loader.config({
paths: {
vs: "https://microsoft.github.io/monaco-editor/node_modules/monaco-editor/min/vs",
},
});
const editorOptions = {
formatOnPaste: true,
minimap: {
enabled: false,
},
};
const StyledWrapper = styled.div`
display: grid;
height: calc(100vh - 36px);
grid-template-columns: 100%;
grid-template-rows: minmax(0, 1fr);
`;
export const MonacoEditor = ({
setHasError,
}: {
setHasError: (value: boolean) => void;
}) => {
const json = useConfig((state) => state.json);
const expand = useConfig((state) => state.expand);
const setJson = useConfig((state) => state.setJson);
const setGraphValue = useGraph((state) => state.setGraphValue);
const [value, setValue] = React.useState<string | undefined>("");
const lightmode = useStored((state) =>
state.lightmode ? "light" : "vs-dark"
);
React.useEffect(() => {
const { nodes, edges } = parser(json, expand);
setGraphValue("nodes", nodes);
setGraphValue("edges", edges);
setValue(json);
}, [expand, json, setGraphValue]);
React.useEffect(() => {
const formatTimer = setTimeout(() => {
try {
if (!value) {
setHasError(false);
return setJson("{}");
}
const parsedJSON = JSON.stringify(JSON.parse(value), null, 2);
setJson(parsedJSON);
setHasError(false);
} catch (jsonError: any) {
setHasError(true);
}
}, 1200);
return () => clearTimeout(formatTimer);
}, [value, setJson, setHasError]);
return (
<StyledWrapper>
<Editor
height="100%"
defaultLanguage="json"
value={value}
theme={lightmode}
options={editorOptions}
onChange={setValue}
loading={<Loading message="Loading Editor..." />}
/>
</StyledWrapper>
);
};

View File

@ -1,16 +1,7 @@
import React from "react";
import styled from "styled-components";
import MonacoEditor, { loader } from "@monaco-editor/react";
import { ErrorContainer } from "src/components/ErrorContainer/ErrorContainer";
import useConfig from "src/hooks/store/useConfig";
import { Loading } from "src/components/Loading";
import useStored from "src/hooks/store/useStored";
loader.config({
paths: {
vs: "https://microsoft.github.io/monaco-editor/node_modules/monaco-editor/min/vs",
},
});
import { ErrorContainer } from "src/components/ErrorContainer";
import { MonacoEditor } from "src/components/MonacoEditor";
const StyledEditorWrapper = styled.div`
display: flex;
@ -19,71 +10,13 @@ const StyledEditorWrapper = styled.div`
overflow: auto;
user-select: none;
`;
const editorOptions = {
formatOnPaste: true,
minimap: {
enabled: false,
},
};
const StyledWrapper = styled.div`
display: grid;
height: calc(100vh - 36px);
grid-template-columns: 100%;
grid-template-rows: minmax(0, 1fr);
`;
export const JsonEditor: React.FC = () => {
const [value, setValue] = React.useState<string | undefined>("");
const [hasError, setHasError] = React.useState(false);
const json = useConfig((state) => state.json);
const lightmode = useStored((state) => state.lightmode);
const setJson = useConfig((state) => state.setJson);
const editorTheme = React.useMemo(
() => (lightmode ? "light" : "vs-dark"),
[lightmode]
);
React.useEffect(() => {
setValue(JSON.stringify(JSON.parse(json), null, 2));
}, [json]);
React.useEffect(() => {
const formatTimer = setTimeout(() => {
try {
if (!value) {
setHasError(false);
return setJson("{}");
}
JSON.parse(value);
setJson(value);
setHasError(false);
} catch (jsonError: any) {
setHasError(true);
}
}, 1500);
return () => clearTimeout(formatTimer);
}, [value, setJson]);
return (
<StyledEditorWrapper>
<ErrorContainer hasError={hasError} />
<StyledWrapper>
<MonacoEditor
height="100%"
defaultLanguage="json"
value={value}
theme={editorTheme}
options={editorOptions}
onChange={setValue}
loading={<Loading message="Loading Editor..." />}
/>
</StyledWrapper>
<MonacoEditor setHasError={setHasError} />
</StyledEditorWrapper>
);
};

View File

@ -0,0 +1,49 @@
import React from "react";
import { NodeModal } from "src/containers/Modals/NodeModal";
import useGraph from "src/hooks/store/useGraph";
import { Graph } from "src/components/Graph";
export const GraphCanvas = ({ isWidget = false }: { isWidget?: boolean }) => {
const [isModalVisible, setModalVisible] = React.useState(false);
const [selectedNode, setSelectedNode] = React.useState<[string, string][]>(
[]
);
const openModal = React.useCallback(() => setModalVisible(true), []);
const collapsedNodes = useGraph((state) => state.collapsedNodes);
const collapsedEdges = useGraph((state) => state.collapsedEdges);
React.useEffect(() => {
const nodeList = collapsedNodes.map((id) => `[id$="node-${id}"]`);
const edgeList = collapsedEdges.map((id) => `[class$="edge-${id}"]`);
const hiddenItems = document.querySelectorAll(".hide");
hiddenItems.forEach((item) => item.classList.remove("hide"));
if (nodeList.length) {
const selectedNodes = document.querySelectorAll(nodeList.join(","));
const selectedEdges = document.querySelectorAll(edgeList.join(","));
selectedNodes.forEach((node) => node.classList.add("hide"));
selectedEdges.forEach((edge) => edge.classList.add("hide"));
}
}, [collapsedNodes, collapsedEdges]);
return (
<>
<Graph
openModal={openModal}
setSelectedNode={setSelectedNode}
isWidget={isWidget}
/>
{!isWidget && (
<NodeModal
selectedNode={selectedNode}
visible={isModalVisible}
closeModal={() => setModalVisible(false)}
/>
)}
</>
);
};

View File

@ -1,7 +1,7 @@
import React from "react";
import styled from "styled-components";
import { Tools } from "src/containers/Editor/Tools";
import { Graph } from "src/components/Graph";
import { GraphCanvas } from "src/containers/Editor/LiveEditor/GraphCanvas";
const StyledLiveEditor = styled.div`
position: relative;
@ -11,7 +11,7 @@ const LiveEditor: React.FC = () => {
return (
<StyledLiveEditor>
<Tools />
<Graph />
<GraphCanvas />
</StyledLiveEditor>
);
};

View File

@ -51,11 +51,13 @@ export const ShareModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
const shareURL = `${baseURL}/editor?json=${encodedJson}`;
React.useEffect(() => {
const jsonEncode = compress(JSON.parse(json));
const jsonString = JSON.stringify(jsonEncode);
setEncodedJson(encodeURIComponent(jsonString));
}, [json]);
if (visible) {
const jsonEncode = compress(JSON.parse(json));
const jsonString = JSON.stringify(jsonEncode);
setEncodedJson(encodeURIComponent(jsonString));
}
}, [json, visible]);
const handleShare = (value: string) => {
navigator.clipboard.writeText(value);

View File

@ -1,5 +1,4 @@
import create from "zustand";
import { Graph } from "src/components/Graph";
import { getChildrenEdges } from "src/utils/getChildrenEdges";
import { getOutgoers } from "src/utils/getOutgoers";