mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Optimize performance through memoization
This commit is contained in:
parent
ee9db2fb05
commit
266db4933a
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useLayoutEffect, useState } from 'react';
|
import { useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
import BadgeHelp from '@/components/man/BadgeHelp';
|
import BadgeHelp from '@/components/man/BadgeHelp';
|
||||||
|
@ -100,6 +100,28 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
});
|
});
|
||||||
}, [substitutes.arguments, template.prototype, updateConstituenta, updateSubstitutes]);
|
}, [substitutes.arguments, template.prototype, updateConstituenta, updateSubstitutes]);
|
||||||
|
|
||||||
|
const templatePanel = useMemo(
|
||||||
|
() => <TemplateTab state={template} partialUpdate={updateTemplate} />,
|
||||||
|
[template, updateTemplate]
|
||||||
|
);
|
||||||
|
|
||||||
|
const argumentsPanel = useMemo(
|
||||||
|
() => <ArgumentsTab schema={schema} state={substitutes} partialUpdate={updateSubstitutes} />,
|
||||||
|
[schema, substitutes, updateSubstitutes]
|
||||||
|
);
|
||||||
|
|
||||||
|
const editorPanel = useMemo(
|
||||||
|
() => (
|
||||||
|
<FormCreateCst
|
||||||
|
state={constituenta}
|
||||||
|
partialUpdate={updateConstituenta}
|
||||||
|
schema={schema}
|
||||||
|
setValidated={setValidated}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[constituenta, updateConstituenta, schema]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
header='Создание конституенты из шаблона'
|
header='Создание конституенты из шаблона'
|
||||||
|
@ -125,21 +147,12 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
<TabLabel label='Конституента' title='Редактирование атрибутов конституенты' className='w-[8rem]' />
|
<TabLabel label='Конституента' title='Редактирование атрибутов конституенты' className='w-[8rem]' />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<TabPanel style={{ display: activeTab === TabID.TEMPLATE ? '' : 'none' }}>
|
<TabPanel style={{ display: activeTab === TabID.TEMPLATE ? '' : 'none' }}>{templatePanel}</TabPanel>
|
||||||
<TemplateTab state={template} partialUpdate={updateTemplate} />
|
|
||||||
</TabPanel>
|
|
||||||
|
|
||||||
<TabPanel style={{ display: activeTab === TabID.ARGUMENTS ? '' : 'none' }}>
|
<TabPanel style={{ display: activeTab === TabID.ARGUMENTS ? '' : 'none' }}>{argumentsPanel}</TabPanel>
|
||||||
<ArgumentsTab schema={schema} state={substitutes} partialUpdate={updateSubstitutes} />
|
|
||||||
</TabPanel>
|
|
||||||
|
|
||||||
<TabPanel className='cc-column' style={{ display: activeTab === TabID.CONSTITUENTA ? '' : 'none' }}>
|
<TabPanel className='cc-column' style={{ display: activeTab === TabID.CONSTITUENTA ? '' : 'none' }}>
|
||||||
<FormCreateCst
|
{editorPanel}
|
||||||
state={constituenta}
|
|
||||||
partialUpdate={updateConstituenta}
|
|
||||||
schema={schema}
|
|
||||||
setValidated={setValidated}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -64,13 +64,8 @@ function DlgEditVersions({ hideWindow, versions, onDelete, onUpdate }: DlgEditVe
|
||||||
setDescription(selected?.description ?? '');
|
setDescription(selected?.description ?? '');
|
||||||
}, [selected]);
|
}, [selected]);
|
||||||
|
|
||||||
return (
|
const versionsTable = useMemo(
|
||||||
<Modal
|
() => (
|
||||||
readonly
|
|
||||||
header='Редактирование версий'
|
|
||||||
hideWindow={hideWindow}
|
|
||||||
className='flex flex-col w-[40rem] px-6 gap-3 pb-6'
|
|
||||||
>
|
|
||||||
<VersionsTable
|
<VersionsTable
|
||||||
processing={processing}
|
processing={processing}
|
||||||
items={versions}
|
items={versions}
|
||||||
|
@ -78,6 +73,18 @@ function DlgEditVersions({ hideWindow, versions, onDelete, onUpdate }: DlgEditVe
|
||||||
onSelect={versionID => setSelected(versions.find(ver => ver.id === versionID))}
|
onSelect={versionID => setSelected(versions.find(ver => ver.id === versionID))}
|
||||||
selected={selected?.id}
|
selected={selected?.id}
|
||||||
/>
|
/>
|
||||||
|
),
|
||||||
|
[processing, versions, onDelete, selected?.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
readonly
|
||||||
|
header='Редактирование версий'
|
||||||
|
hideWindow={hideWindow}
|
||||||
|
className='flex flex-col w-[40rem] px-6 gap-3 pb-6'
|
||||||
|
>
|
||||||
|
{versionsTable}
|
||||||
<div className='flex'>
|
<div className='flex'>
|
||||||
<TextInput
|
<TextInput
|
||||||
id='dlg_version'
|
id='dlg_version'
|
||||||
|
|
|
@ -58,6 +58,27 @@ function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInli
|
||||||
setSubstitutions([]);
|
setSubstitutions([]);
|
||||||
}, [source.schema]);
|
}, [source.schema]);
|
||||||
|
|
||||||
|
const schemaPanel = useMemo(() => <SchemaTab selected={donorID} setSelected={setDonorID} />, [donorID]);
|
||||||
|
const itemsPanel = useMemo(
|
||||||
|
() => (
|
||||||
|
<ConstituentsTab schema={source.schema} loading={source.loading} selected={selected} setSelected={setSelected} />
|
||||||
|
),
|
||||||
|
[source.schema, source.loading, selected]
|
||||||
|
);
|
||||||
|
const substitutesPanel = useMemo(
|
||||||
|
() => (
|
||||||
|
<SubstitutionsTab
|
||||||
|
receiver={receiver}
|
||||||
|
source={source.schema}
|
||||||
|
selected={selected}
|
||||||
|
loading={source.loading}
|
||||||
|
substitutions={substitutions}
|
||||||
|
setSubstitutions={setSubstitutions}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[source.schema, source.loading, receiver, selected, substitutions]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
header='Импорт концептуальной схем'
|
header='Импорт концептуальной схем'
|
||||||
|
@ -80,29 +101,9 @@ function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInli
|
||||||
<TabLabel label='Отождествления' title='Таблица отождествлений' className='w-[8rem]' />
|
<TabLabel label='Отождествления' title='Таблица отождествлений' className='w-[8rem]' />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<TabPanel style={{ display: activeTab === TabID.SCHEMA ? '' : 'none' }}>
|
<TabPanel style={{ display: activeTab === TabID.SCHEMA ? '' : 'none' }}>{schemaPanel}</TabPanel>
|
||||||
<SchemaTab selected={donorID} setSelected={setDonorID} />
|
<TabPanel style={{ display: activeTab === TabID.SELECTIONS ? '' : 'none' }}>{itemsPanel}</TabPanel>
|
||||||
</TabPanel>
|
<TabPanel style={{ display: activeTab === TabID.SUBSTITUTIONS ? '' : 'none' }}>{substitutesPanel}</TabPanel>
|
||||||
|
|
||||||
<TabPanel style={{ display: activeTab === TabID.SELECTIONS ? '' : 'none' }}>
|
|
||||||
<ConstituentsTab
|
|
||||||
schema={source.schema}
|
|
||||||
loading={source.loading}
|
|
||||||
selected={selected}
|
|
||||||
setSelected={setSelected}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
|
|
||||||
<TabPanel style={{ display: activeTab === TabID.SUBSTITUTIONS ? '' : 'none' }}>
|
|
||||||
<SubstitutionsTab
|
|
||||||
receiver={receiver}
|
|
||||||
source={source.schema}
|
|
||||||
selected={selected}
|
|
||||||
loading={source.loading}
|
|
||||||
substitutions={substitutions}
|
|
||||||
setSubstitutions={setSubstitutions}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
import DataLoader from '@/components/wrap/DataLoader';
|
import DataLoader from '@/components/wrap/DataLoader';
|
||||||
|
@ -61,6 +61,16 @@ function LibraryPage() {
|
||||||
setFilter({});
|
setFilter({});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const view = useMemo(
|
||||||
|
() => (
|
||||||
|
<ViewLibrary
|
||||||
|
resetQuery={resetQuery} //
|
||||||
|
items={items}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[resetQuery, items]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataLoader
|
<DataLoader
|
||||||
id='library-page' //
|
id='library-page' //
|
||||||
|
@ -76,10 +86,7 @@ function LibraryPage() {
|
||||||
filtered={items.length}
|
filtered={items.length}
|
||||||
setFilter={setFilter}
|
setFilter={setFilter}
|
||||||
/>
|
/>
|
||||||
<ViewLibrary
|
{view}
|
||||||
resetQuery={resetQuery} //
|
|
||||||
items={items}
|
|
||||||
/>
|
|
||||||
</DataLoader>
|
</DataLoader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
||||||
import { AnimatePresence } from 'framer-motion';
|
import { AnimatePresence } from 'framer-motion';
|
||||||
import { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { FaRegKeyboard } from 'react-icons/fa6';
|
import { FaRegKeyboard } from 'react-icons/fa6';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
@ -152,6 +152,17 @@ function EditorRSExpression({
|
||||||
setMathFont(mathFont === 'math' ? 'math2' : 'math');
|
setMathFont(mathFont === 'math' ? 'math2' : 'math');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const controls = useMemo(
|
||||||
|
() => (
|
||||||
|
<RSEditorControls
|
||||||
|
isOpen={showControls && (!disabled || model.processing)}
|
||||||
|
disabled={disabled}
|
||||||
|
onEdit={handleEdit}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[showControls, disabled, model.processing, handleEdit]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
|
@ -208,11 +219,7 @@ function EditorRSExpression({
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RSEditorControls
|
{controls}
|
||||||
isOpen={showControls && (!disabled || model.processing)}
|
|
||||||
disabled={disabled}
|
|
||||||
onEdit={handleEdit}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ParsingResult
|
<ParsingResult
|
||||||
isOpen={!!parser.parseData && parser.parseData.errors.length > 0}
|
isOpen={!!parser.parseData && parser.parseData.errors.length > 0}
|
||||||
|
|
|
@ -164,6 +164,30 @@ function RSTabs() {
|
||||||
|
|
||||||
const panelHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
|
const panelHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
|
||||||
|
|
||||||
|
const cardPanel = useMemo(
|
||||||
|
() => (
|
||||||
|
<EditorRSForm
|
||||||
|
isModified={isModified} // prettier: split lines
|
||||||
|
setIsModified={setIsModified}
|
||||||
|
onDestroy={onDestroySchema}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[isModified, onDestroySchema]
|
||||||
|
);
|
||||||
|
|
||||||
|
const listPanel = useMemo(() => <EditorRSList onOpenEdit={onOpenCst} />, [onOpenCst]);
|
||||||
|
const editorPanel = useMemo(
|
||||||
|
() => (
|
||||||
|
<EditorConstituenta
|
||||||
|
isModified={isModified}
|
||||||
|
setIsModified={setIsModified}
|
||||||
|
activeCst={activeCst}
|
||||||
|
onOpenEdit={onOpenCst}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[isModified, setIsModified, activeCst, onOpenCst]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RSEditState
|
<RSEditState
|
||||||
selected={selected}
|
selected={selected}
|
||||||
|
@ -198,24 +222,15 @@ function RSTabs() {
|
||||||
|
|
||||||
<AnimateFade className='overflow-y-auto' style={{ maxHeight: panelHeight }}>
|
<AnimateFade className='overflow-y-auto' style={{ maxHeight: panelHeight }}>
|
||||||
<TabPanel forceRender style={{ display: activeTab === RSTabID.CARD ? '' : 'none' }}>
|
<TabPanel forceRender style={{ display: activeTab === RSTabID.CARD ? '' : 'none' }}>
|
||||||
<EditorRSForm
|
{cardPanel}
|
||||||
isModified={isModified} // prettier: split lines
|
|
||||||
setIsModified={setIsModified}
|
|
||||||
onDestroy={onDestroySchema}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel forceRender style={{ display: activeTab === RSTabID.CST_LIST ? '' : 'none' }}>
|
<TabPanel forceRender style={{ display: activeTab === RSTabID.CST_LIST ? '' : 'none' }}>
|
||||||
<EditorRSList onOpenEdit={onOpenCst} />
|
{listPanel}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel forceRender style={{ display: activeTab === RSTabID.CST_EDIT ? '' : 'none' }}>
|
<TabPanel forceRender style={{ display: activeTab === RSTabID.CST_EDIT ? '' : 'none' }}>
|
||||||
<EditorConstituenta
|
{editorPanel}
|
||||||
isModified={isModified}
|
|
||||||
setIsModified={setIsModified}
|
|
||||||
activeCst={activeCst}
|
|
||||||
onOpenEdit={onOpenCst}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel style={{ display: activeTab === RSTabID.TERM_GRAPH ? '' : 'none' }}>
|
<TabPanel style={{ display: activeTab === RSTabID.TERM_GRAPH ? '' : 'none' }}>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
|
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
|
||||||
|
@ -27,6 +27,19 @@ function ViewConstituents({ expression, schema, activeID, isBottom, onOpenEdit }
|
||||||
|
|
||||||
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
|
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
|
||||||
|
|
||||||
|
const table = useMemo(
|
||||||
|
() => (
|
||||||
|
<ConstituentsTable
|
||||||
|
maxHeight={isBottom ? '12rem' : calculateHeight('8.2rem')}
|
||||||
|
items={filteredData}
|
||||||
|
activeID={activeID}
|
||||||
|
onOpenEdit={onOpenEdit}
|
||||||
|
denseThreshold={COLUMN_EXPRESSION_HIDE_THRESHOLD}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
[isBottom, filteredData, activeID, onOpenEdit, calculateHeight]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -46,13 +59,7 @@ function ViewConstituents({ expression, schema, activeID, isBottom, onOpenEdit }
|
||||||
activeExpression={expression}
|
activeExpression={expression}
|
||||||
setFiltered={setFilteredData}
|
setFiltered={setFilteredData}
|
||||||
/>
|
/>
|
||||||
<ConstituentsTable
|
{table}
|
||||||
maxHeight={isBottom ? '12rem' : calculateHeight('8.2rem')}
|
|
||||||
items={filteredData}
|
|
||||||
activeID={activeID}
|
|
||||||
onOpenEdit={onOpenEdit}
|
|
||||||
denseThreshold={COLUMN_EXPRESSION_HIDE_THRESHOLD}
|
|
||||||
/>
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user