From 2183d659e7a46f79a7908470ccb9815e87c6a191 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:55:26 +0300 Subject: [PATCH] R: Remove redundant useEffect --- .../select/PickMultiConstituenta.tsx | 31 ++------ .../src/components/select/PickSchema.tsx | 26 +++---- .../components/select/SelectMultiGrammeme.tsx | 14 +--- .../frontend/src/models/miscellaneousAPI.ts | 65 +++++++++++++++- .../EditorConstituenta/FormConstituenta.tsx | 1 + .../RSFormPage/EditorRSList/EditorRSList.tsx | 32 ++------ .../RSFormPage/EditorTermGraph/TGFlow.tsx | 4 +- .../EditorTermGraph/useGraphFilter.ts | 75 ------------------- .../ViewConstituents/ConstituentsSearch.tsx | 4 +- 9 files changed, 95 insertions(+), 157 deletions(-) delete mode 100644 rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/useGraphFilter.ts diff --git a/rsconcept/frontend/src/components/select/PickMultiConstituenta.tsx b/rsconcept/frontend/src/components/select/PickMultiConstituenta.tsx index 6286d558..47119490 100644 --- a/rsconcept/frontend/src/components/select/PickMultiConstituenta.tsx +++ b/rsconcept/frontend/src/components/select/PickMultiConstituenta.tsx @@ -1,7 +1,7 @@ 'use client'; import clsx from 'clsx'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import BadgeConstituenta from '@/components/info/BadgeConstituenta'; import { CProps } from '@/components/props'; @@ -41,12 +41,13 @@ function PickMultiConstituenta({ className, ...restProps }: PickMultiConstituentaProps) { - const [rowSelection, setRowSelection] = useState({}); const [filterText, setFilterText] = useState(''); - const [filtered, setFiltered] = useState(items); + const filtered = filterText ? items.filter(cst => matchConstituenta(cst, filterText, CstMatchMode.ALL)) : items; + const rowSelection: RowSelectionState = Object.fromEntries( + filtered.map((cst, index) => [String(index), value.includes(cst.id)]) + ); - // TODO: extract graph fold logic to separate function const foldedGraph = (() => { if (items.length === schema.items.length) { return schema.graph; @@ -66,28 +67,6 @@ function PickMultiConstituenta({ return newGraph; })(); - useEffect(() => { - if (filtered.length === 0) { - setRowSelection({}); - return; - } - const newRowSelection: RowSelectionState = {}; - filtered.forEach((cst, index) => { - newRowSelection[String(index)] = value.includes(cst.id); - }); - setRowSelection(newRowSelection); - }, [filtered, setRowSelection, value]); - - useEffect(() => { - if (items.length === 0) { - setFiltered([]); - } else if (filterText) { - setFiltered(items.filter(cst => matchConstituenta(cst, filterText, CstMatchMode.ALL))); - } else { - setFiltered(items); - } - }, [filterText, items]); - function handleRowSelection(updater: React.SetStateAction) { if (!items) { onChange([]); diff --git a/rsconcept/frontend/src/components/select/PickSchema.tsx b/rsconcept/frontend/src/components/select/PickSchema.tsx index e36492b2..f74612f5 100644 --- a/rsconcept/frontend/src/components/select/PickSchema.tsx +++ b/rsconcept/frontend/src/components/select/PickSchema.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useIntl } from 'react-intl'; import { IconClose, IconFolderTree } from '@/components/Icons'; @@ -45,22 +45,18 @@ function PickSchema({ ...restProps }: PickSchemaProps) { const intl = useIntl(); - const [filterText, setFilterText] = useState(initialFilter); - const [filterLocation, setFilterLocation] = useState(''); - const [filtered, setFiltered] = useState([]); - const baseFiltered = items.filter(item => item.item_type === itemType && (!baseFilter || baseFilter(item))); - const locationMenu = useDropdown(); - useEffect(() => { - let newFiltered = baseFiltered.filter(item => matchLibraryItem(item, filterText)); - if (filterLocation.length > 0) { - newFiltered = newFiltered.filter( - item => item.location === filterLocation || item.location.startsWith(`${filterLocation}/`) - ); - } - setFiltered(newFiltered); - }, [filterText, filterLocation, baseFiltered]); + const [filterText, setFilterText] = useState(initialFilter); + const [filterLocation, setFilterLocation] = useState(''); + + const baseFiltered = items + .filter(item => item.item_type === itemType && (!baseFilter || baseFilter(item))) + .filter(item => matchLibraryItem(item, filterText)); + const filtered = + filterLocation.length > 0 + ? baseFiltered.filter(item => item.location === filterLocation || item.location.startsWith(`${filterLocation}/`)) + : baseFiltered; const columns = [ columnHelper.accessor('alias', { diff --git a/rsconcept/frontend/src/components/select/SelectMultiGrammeme.tsx b/rsconcept/frontend/src/components/select/SelectMultiGrammeme.tsx index 9dc60669..78dba411 100644 --- a/rsconcept/frontend/src/components/select/SelectMultiGrammeme.tsx +++ b/rsconcept/frontend/src/components/select/SelectMultiGrammeme.tsx @@ -1,5 +1,3 @@ -import { useEffect, useState } from 'react'; - import { CProps } from '@/components/props'; import SelectMulti, { SelectMultiProps } from '@/components/ui/SelectMulti'; import { Grammeme } from '@/models/language'; @@ -15,14 +13,10 @@ interface SelectMultiGrammemeProps } function SelectMultiGrammeme({ value, onChange, ...restProps }: SelectMultiGrammemeProps) { - const [options, setOptions] = useState([]); - - useEffect(() => { - const compatible = getCompatibleGrams( - value.filter(data => Object.values(Grammeme).includes(data.value as Grammeme)).map(data => data.value as Grammeme) - ); - setOptions(SelectorGrammemes.filter(({ value }) => compatible.includes(value as Grammeme))); - }, [value]); + const compatible = getCompatibleGrams( + value.filter(data => Object.values(Grammeme).includes(data.value as Grammeme)).map(data => data.value as Grammeme) + ); + const options = SelectorGrammemes.filter(({ value }) => compatible.includes(value as Grammeme)); return ( { + const result: CstType[] = []; + if (params.allowBase) result.push(CstType.BASE); + if (params.allowStruct) result.push(CstType.STRUCTURED); + if (params.allowTerm) result.push(CstType.TERM); + if (params.allowAxiom) result.push(CstType.AXIOM); + if (params.allowFunction) result.push(CstType.FUNCTION); + if (params.allowPredicate) result.push(CstType.PREDICATE); + if (params.allowConstant) result.push(CstType.CONSTANT); + if (params.allowTheorem) result.push(CstType.THEOREM); + return result; + })(); + + if (params.noHermits) { + filtered.removeIsolated(); + } + if (params.noTemplates) { + schema.items.forEach(cst => { + if (cst !== focusCst && cst.is_template) { + filtered.foldNode(cst.id); + } + }); + } + if (allowedTypes.length < Object.values(CstType).length) { + schema.items.forEach(cst => { + if (cst !== focusCst && !allowedTypes.includes(cst.cst_type)) { + filtered.foldNode(cst.id); + } + }); + } + if (!focusCst && params.foldDerived) { + schema.items.forEach(cst => { + if (cst.spawner) { + filtered.foldNode(cst.id); + } + }); + } + if (focusCst) { + const includes: ConstituentaID[] = [ + focusCst.id, + ...focusCst.spawn, + ...(params.focusShowInputs ? schema.graph.expandInputs([focusCst.id]) : []), + ...(params.focusShowOutputs ? schema.graph.expandOutputs([focusCst.id]) : []) + ]; + schema.items.forEach(cst => { + if (!includes.includes(cst.id)) { + filtered.foldNode(cst.id); + } + }); + } + if (params.noTransitive) { + filtered.transitiveReduction(); + } + + return filtered; +} diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx index 5f01f259..d8dd51f5 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx @@ -49,6 +49,7 @@ function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpen } = useForm({ resolver: zodResolver(CstUpdateSchema) }); const [localParse, setLocalParse] = useState(undefined); + const typification = localParse ? labelTypification({ isValid: localParse.parseResult, diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/EditorRSList.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/EditorRSList.tsx index caa51143..3a39e13b 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/EditorRSList.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/EditorRSList.tsx @@ -1,7 +1,7 @@ 'use client'; import fileDownload from 'js-file-download'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { toast } from 'react-toastify'; import { useMutatingRSForm } from '@/backend/rsform/useMutatingRSForm'; @@ -11,7 +11,7 @@ import MiniButton from '@/components/ui/MiniButton'; import Overlay from '@/components/ui/Overlay'; import SearchBar from '@/components/ui/SearchBar'; import { CstMatchMode } from '@/models/miscellaneous'; -import { ConstituentaID, CstType, IConstituenta } from '@/models/rsform'; +import { ConstituentaID, CstType } from '@/models/rsform'; import { matchConstituenta } from '@/models/rsformAPI'; import { useFitHeight } from '@/stores/appLayout'; import { information } from '@/utils/labels'; @@ -22,34 +22,18 @@ import TableRSList from './TableRSList'; import ToolbarRSList from './ToolbarRSList'; function EditorRSList() { - const [rowSelection, setRowSelection] = useState({}); const controller = useRSEdit(); const isProcessing = useMutatingRSForm(); - const [filtered, setFiltered] = useState(controller.schema.items); const [filterText, setFilterText] = useState(''); - useEffect(() => { - if (filtered.length === 0) { - setRowSelection({}); - return; - } - const newRowSelection: RowSelectionState = {}; - filtered.forEach((cst, index) => { - newRowSelection[String(index)] = controller.selected.includes(cst.id); - }); - setRowSelection(newRowSelection); - }, [filtered, setRowSelection, controller.selected]); + const filtered = filterText + ? controller.schema.items.filter(cst => matchConstituenta(cst, filterText, CstMatchMode.ALL)) + : controller.schema.items; - useEffect(() => { - if (controller.schema.items.length === 0) { - setFiltered([]); - } else if (filterText) { - setFiltered(controller.schema.items.filter(cst => matchConstituenta(cst, filterText, CstMatchMode.ALL))); - } else { - setFiltered(controller.schema.items); - } - }, [filterText, controller.schema.items]); + const rowSelection: RowSelectionState = Object.fromEntries( + filtered.map((cst, index) => [String(index), controller.selected.includes(cst.id)]) + ); function handleDownloadCSV() { if (filtered.length === 0) { diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/TGFlow.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/TGFlow.tsx index cc2bd19d..9b26c3ec 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/TGFlow.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/TGFlow.tsx @@ -25,6 +25,7 @@ import SelectedCounter from '@/components/info/SelectedCounter'; import { CProps } from '@/components/props'; import ToolbarGraphSelection from '@/components/select/ToolbarGraphSelection'; import Overlay from '@/components/ui/Overlay'; +import { produceFilteredGraph } from '@/models/miscellaneousAPI'; import { ConstituentaID, CstType, IConstituenta } from '@/models/rsform'; import { isBasicConcept } from '@/models/rsformAPI'; import { useMainHeight } from '@/stores/appLayout'; @@ -42,7 +43,6 @@ import { TGNodeTypes } from './graph/TGNodeTypes'; import GraphSelectors from './GraphSelectors'; import ToolbarFocusedCst from './ToolbarFocusedCst'; import ToolbarTermGraph from './ToolbarTermGraph'; -import useGraphFilter from './useGraphFilter'; import ViewHidden from './ViewHidden'; const ZOOM_MAX = 3; @@ -67,7 +67,7 @@ function TGFlow() { const [edges, setEdges] = useEdgesState([]); const [focusCst, setFocusCst] = useState(undefined); - const filteredGraph = useGraphFilter(controller.schema, filter, focusCst); + const filteredGraph = produceFilteredGraph(controller.schema, filter, focusCst); const [hidden, setHidden] = useState([]); const [isDragging, setIsDragging] = useState(false); diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/useGraphFilter.ts b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/useGraphFilter.ts deleted file mode 100644 index 3ce8e95d..00000000 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/useGraphFilter.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { useEffect, useState } from 'react'; - -import { Graph } from '@/models/Graph'; -import { GraphFilterParams } from '@/models/miscellaneous'; -import { ConstituentaID, CstType, IConstituenta, IRSForm } from '@/models/rsform'; - -function useGraphFilter(schema: IRSForm | undefined, params: GraphFilterParams, focusCst: IConstituenta | undefined) { - const [filtered, setFiltered] = useState(new Graph()); - - const allowedTypes: CstType[] = (() => { - const result: CstType[] = []; - if (params.allowBase) result.push(CstType.BASE); - if (params.allowStruct) result.push(CstType.STRUCTURED); - if (params.allowTerm) result.push(CstType.TERM); - if (params.allowAxiom) result.push(CstType.AXIOM); - if (params.allowFunction) result.push(CstType.FUNCTION); - if (params.allowPredicate) result.push(CstType.PREDICATE); - if (params.allowConstant) result.push(CstType.CONSTANT); - if (params.allowTheorem) result.push(CstType.THEOREM); - return result; - })(); - - useEffect(() => { - if (!schema) { - setFiltered(new Graph()); - return; - } - const graph = schema.graph.clone(); - if (params.noHermits) { - graph.removeIsolated(); - } - if (params.noTemplates) { - schema.items.forEach(cst => { - if (cst !== focusCst && cst.is_template) { - graph.foldNode(cst.id); - } - }); - } - if (allowedTypes.length < Object.values(CstType).length) { - schema.items.forEach(cst => { - if (cst !== focusCst && !allowedTypes.includes(cst.cst_type)) { - graph.foldNode(cst.id); - } - }); - } - if (!focusCst && params.foldDerived) { - schema.items.forEach(cst => { - if (cst.spawner) { - graph.foldNode(cst.id); - } - }); - } - if (focusCst) { - const includes: ConstituentaID[] = [ - focusCst.id, - ...focusCst.spawn, - ...(params.focusShowInputs ? schema.graph.expandInputs([focusCst.id]) : []), - ...(params.focusShowOutputs ? schema.graph.expandOutputs([focusCst.id]) : []) - ]; - schema.items.forEach(cst => { - if (!includes.includes(cst.id)) { - graph.foldNode(cst.id); - } - }); - } - if (params.noTransitive) { - graph.transitiveReduction(); - } - setFiltered(graph); - }, [schema, params, allowedTypes, focusCst]); - - return filtered; -} - -export default useGraphFilter; diff --git a/rsconcept/frontend/src/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx b/rsconcept/frontend/src/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx index 0882254f..d93c15b7 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx @@ -7,7 +7,7 @@ import SelectGraphFilter from '@/components/select/SelectGraphFilter'; import SelectMatchMode from '@/components/select/SelectMatchMode'; import MiniButton from '@/components/ui/MiniButton'; import SearchBar from '@/components/ui/SearchBar'; -import { applyGraphFilter } from '@/models/miscellaneousAPI'; +import { applyGraphQuery } from '@/models/miscellaneousAPI'; import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform'; import { matchConstituenta } from '@/models/rsformAPI'; import { useCstSearchStore } from '@/stores/cstSearch'; @@ -40,7 +40,7 @@ function ConstituentsSearch({ schema, activeID, activeExpression, dense, onChang if (!activeID) { result = schema.items; } else { - result = applyGraphFilter(schema, activeID, filterSource); + result = applyGraphQuery(schema, activeID, filterSource); } if (query) { result = result.filter(cst => matchConstituenta(cst, query, filterMatch));