Removed use-context-selector completely (#12139)

This PR removes use-context-selector completely, so that any bug
associated with state synchronization between recoil and
use-context-selector disappears.

There might be a slight performance decrease on the table, but since we
have already improved the average performance per line by a lot, and
that the performance bottleneck right now is the fetch more logic and
the windowing solution we use, it is not relevant.

Also the DX has become so hindered by this parallel state logic recently
(think [cache
invalidation](https://martinfowler.com/bliki/TwoHardThings.html)), that
the main benefit we gain from this removal is the DX improvement.

Fixes https://github.com/twentyhq/twenty/issues/12123
Fixes https://github.com/twentyhq/twenty/issues/12109
This commit is contained in:
Lucas Bordeau
2025-05-20 13:35:28 +02:00
committed by GitHub
parent 9ba24b3654
commit 0553f58c52
30 changed files with 408 additions and 697 deletions

View File

@ -2,7 +2,6 @@ import { useContext } from 'react';
import { useRecoilCallback } from 'recoil';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { useSetRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { generateEmptyFieldValue } from '@/object-record/utils/generateEmptyFieldValue';
@ -17,8 +16,6 @@ export const useClearField = () => {
const [updateRecord] = useUpdateRecord();
const setRecordFieldValue = useSetRecordFieldValue();
const clearField = useRecoilCallback(
({ snapshot, set }) =>
() => {
@ -51,8 +48,6 @@ export const useClearField = () => {
emptyFieldValue,
);
setRecordFieldValue(recordId, fieldName, emptyFieldValue);
updateRecord?.({
variables: {
where: { id: recordId },
@ -62,7 +57,7 @@ export const useClearField = () => {
},
});
},
[recordId, fieldDefinition, updateRecord, setRecordFieldValue],
[recordId, fieldDefinition, updateRecord],
);
return clearField;

View File

@ -1,10 +1,10 @@
import { useContext } from 'react';
import { isFieldValueEmpty } from '@/object-record/record-field/utils/isFieldValueEmpty';
import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { FieldContext } from '../contexts/FieldContext';
import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { isDefined } from 'twenty-shared/utils';
import { FieldContext } from '../contexts/FieldContext';
export const useIsFieldEmpty = () => {
const { recordId, fieldDefinition, overridenIsFieldEmpty } =

View File

@ -1,102 +0,0 @@
import { Meta, StoryObj } from '@storybook/react';
import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { RelationFromManyFieldDisplay } from '@/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay';
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import {
RecordFieldValueSelectorContextProvider,
useSetRecordFieldValue,
} from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator';
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
import { ComponentDecorator } from 'twenty-ui/testing';
import {
fieldValue,
otherPersonMock,
relationFromManyFieldDisplayMock,
} from './relationFromManyFieldDisplayMock';
const RelationFieldValueSetterEffect = () => {
const setEntity = useSetRecoilState(
recordStoreFamilyState(relationFromManyFieldDisplayMock.recordId),
);
const setRelationEntity = useSetRecoilState(
recordStoreFamilyState(relationFromManyFieldDisplayMock.relationRecordId),
);
const setRecordFieldValue = useSetRecordFieldValue();
useEffect(() => {
setEntity(relationFromManyFieldDisplayMock.entityValue);
setRelationEntity(relationFromManyFieldDisplayMock.relationFieldValue);
setRecordFieldValue(
relationFromManyFieldDisplayMock.entityValue.id,
'company',
[relationFromManyFieldDisplayMock.entityValue],
);
setRecordFieldValue(otherPersonMock.entityValue.id, 'company', [
relationFromManyFieldDisplayMock.entityValue,
]);
setRecordFieldValue(
relationFromManyFieldDisplayMock.relationFieldValue.id,
'company',
relationFromManyFieldDisplayMock.relationFieldValue,
);
}, [setEntity, setRelationEntity, setRecordFieldValue]);
return null;
};
const meta: Meta = {
title: 'UI/Data/Field/Display/RelationFromManyFieldDisplay',
decorators: [
MemoryRouterDecorator,
ChipGeneratorsDecorator,
(Story) => (
<RecordFieldValueSelectorContextProvider>
<FieldContext.Provider
value={{
recordId: relationFromManyFieldDisplayMock.recordId,
isLabelIdentifier: false,
fieldDefinition: {
...relationFromManyFieldDisplayMock.fieldDefinition,
} as unknown as FieldDefinition<FieldMetadata>,
isReadOnly: false,
}}
>
<RelationFieldValueSetterEffect />
<Story />
</FieldContext.Provider>
</RecordFieldValueSelectorContextProvider>
),
ComponentDecorator,
],
component: RelationFromManyFieldDisplay,
argTypes: { value: { control: 'date' } },
args: { fieldValue: fieldValue },
parameters: {
chromatic: { disableSnapshot: true },
},
};
export default meta;
type Story = StoryObj<typeof RelationFromManyFieldDisplay>;
export const Default: Story = {};
// TODO: optimize this component once we have morph many
export const Performance = getProfilingStory({
componentName: 'RelationFromManyFieldDisplay',
averageThresholdInMs: 1,
numberOfRuns: 20,
numberOfTestsPerRun: 100,
});

View File

@ -1,13 +1,13 @@
import { isNonEmptyString } from '@sniptt/guards';
import { useContext } from 'react';
import { PreComputedChipGeneratorsContext } from '@/object-metadata/contexts/PreComputedChipGeneratorsContext';
import { isFieldFullName } from '@/object-record/record-field/types/guards/isFieldFullName';
import { isFieldNumber } from '@/object-record/record-field/types/guards/isFieldNumber';
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
import { useRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { isNonEmptyString } from '@sniptt/guards';
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { isFieldActor } from '@/object-record/record-field/types/guards/isFieldActor';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { isDefined } from 'twenty-shared/utils';
import { FieldContext } from '../../contexts/FieldContext';
@ -38,7 +38,7 @@ export const useChipFieldDisplay = () => {
? fieldDefinition.metadata.objectMetadataNameSingular
: undefined;
const recordValue = useRecordValue(recordId);
const recordValue = useRecoilValue(recordStoreFamilyState(recordId));
if (!isNonEmptyString(objectNameSingular)) {
throw new Error('Object metadata name singular is not a non-empty string');

View File

@ -11,7 +11,6 @@ import { recordIndexViewTypeState } from '@/object-record/record-index/states/re
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
@ -48,48 +47,46 @@ export const RecordIndexContainer = () => {
<>
<StyledContainer>
<InformationBannerWrapper />
<RecordFieldValueSelectorContextProvider>
<SpreadsheetImportProvider>
<ViewBar
viewBarId={recordIndexId}
optionsDropdownButton={
<ObjectOptionsDropdown
recordIndexId={recordIndexId}
objectMetadataItem={objectMetadataItem}
viewType={recordIndexViewType ?? ViewType.Table}
/>
}
/>
<RecordIndexViewBarEffect
objectNamePlural={objectNamePlural}
<SpreadsheetImportProvider>
<ViewBar
viewBarId={recordIndexId}
optionsDropdownButton={
<ObjectOptionsDropdown
recordIndexId={recordIndexId}
objectMetadataItem={objectMetadataItem}
viewType={recordIndexViewType ?? ViewType.Table}
/>
}
/>
<RecordIndexViewBarEffect
objectNamePlural={objectNamePlural}
viewBarId={recordIndexId}
/>
</SpreadsheetImportProvider>
<RecordIndexFiltersToContextStoreEffect />
{recordIndexViewType === ViewType.Table && (
<>
<RecordIndexTableContainer
recordTableId={recordIndexId}
viewBarId={recordIndexId}
/>
</SpreadsheetImportProvider>
<RecordIndexFiltersToContextStoreEffect />
{recordIndexViewType === ViewType.Table && (
<>
<RecordIndexTableContainer
recordTableId={recordIndexId}
viewBarId={recordIndexId}
/>
<RecordIndexTableContainerEffect />
</>
)}
{recordIndexViewType === ViewType.Kanban && (
<StyledContainerWithPadding>
<RecordIndexBoardContainer
recordBoardId={recordIndexId}
viewBarId={recordIndexId}
objectNameSingular={objectNameSingular}
/>
<RecordIndexBoardDataLoader
objectNameSingular={objectNameSingular}
recordBoardId={recordIndexId}
/>
<RecordIndexBoardDataLoaderEffect recordBoardId={recordIndexId} />
</StyledContainerWithPadding>
)}
</RecordFieldValueSelectorContextProvider>
<RecordIndexTableContainerEffect />
</>
)}
{recordIndexViewType === ViewType.Kanban && (
<StyledContainerWithPadding>
<RecordIndexBoardContainer
recordBoardId={recordIndexId}
viewBarId={recordIndexId}
objectNameSingular={objectNameSingular}
/>
<RecordIndexBoardDataLoader
objectNameSingular={objectNameSingular}
recordBoardId={recordIndexId}
/>
<RecordIndexBoardDataLoaderEffect recordBoardId={recordIndexId} />
</StyledContainerWithPadding>
)}
</StyledContainer>
</>
);

View File

@ -14,7 +14,7 @@ import { useRecordBoardRecordGqlFields } from '@/object-record/record-index/hook
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { isDefined } from 'twenty-shared/utils';
@ -32,7 +32,6 @@ export const useLoadRecordIndexBoardColumn = ({
recordBoardId,
columnId,
}: UseLoadRecordIndexBoardProps) => {
const setRecordValueInContextSelector = useSetRecordValue();
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular,
});
@ -102,10 +101,7 @@ export const useLoadRecordIndexBoardColumn = ({
useEffect(() => {
upsertRecordsInStore(records);
for (const record of records) {
setRecordValueInContextSelector(record.id, record);
}
}, [records, upsertRecordsInStore, setRecordValueInContextSelector]);
}, [records, upsertRecordsInStore]);
return {
records,

View File

@ -2,7 +2,6 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { buildFindOneRecordForShowPageOperationSignature } from '@/object-record/record-show/graphql/operations/factories/findOneRecordForShowPageOperationSignatureFactory';
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { useEffect } from 'react';
@ -19,7 +18,6 @@ export const RecordShowEffect = ({
}: RecordShowEffectProps) => {
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
const { objectMetadataItems } = useObjectMetadataItems();
const setRecordValueInContextSelector = useSetRecordValue();
const FIND_ONE_RECORD_FOR_SHOW_PAGE_OPERATION_SIGNATURE =
buildFindOneRecordForShowPageOperationSignature({
@ -44,10 +42,8 @@ export const RecordShowEffect = ({
if (JSON.stringify(previousRecordValue) !== JSON.stringify(newRecord)) {
set(recordStoreFamilyState(recordId), newRecord);
}
setRecordValueInContextSelector(recordId, newRecord);
},
[recordId, setRecordValueInContextSelector],
[recordId],
);
useEffect(() => {

View File

@ -3,7 +3,7 @@ import { useContext, useEffect } from 'react';
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { FieldRelationMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { isDefined } from 'twenty-shared/utils';
@ -14,8 +14,6 @@ type RecordDetailRelationRecordsListItemEffectProps = {
export const RecordDetailRelationRecordsListItemEffect = ({
relationRecordId,
}: RecordDetailRelationRecordsListItemEffectProps) => {
const setRecordValueInContextSelector = useSetRecordValue();
const { fieldDefinition } = useContext(FieldContext);
const { relationObjectMetadataNameSingular } =
@ -31,9 +29,8 @@ export const RecordDetailRelationRecordsListItemEffect = ({
useEffect(() => {
if (isDefined(record)) {
upsertRecords([record]);
setRecordValueInContextSelector(record.id, record);
}
}, [record, upsertRecords, setRecordValueInContextSelector]);
}, [record, upsertRecords]);
return null;
};

View File

@ -1,78 +1,16 @@
import { Dispatch, SetStateAction, useState } from 'react';
import { createContext, useContextSelector } from 'use-context-selector';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
export type RecordFieldValue = {
[recordId: string]: {
[fieldName: string]: any;
};
};
export const RecordFieldValueSelectorContext = createContext<
[RecordFieldValue, Dispatch<SetStateAction<RecordFieldValue>>]
>([{}, () => {}]);
export const useSetRecordValue = () => {
const setTableValue = useContextSelector(
RecordFieldValueSelectorContext,
(value) => value[1],
);
return (recordId: string, newRecord: any) => {
setTableValue((currentTable) => ({
...currentTable,
[recordId]: newRecord,
}));
};
};
export const useRecordValue = (recordId: string) => {
const tableValue = useContextSelector(
RecordFieldValueSelectorContext,
(value) => value[0]?.[recordId],
);
return tableValue as ObjectRecord | undefined;
};
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
import { useRecoilValue } from 'recoil';
export const useRecordFieldValue = <T,>(
recordId: string,
fieldName: string,
) => {
const recordFieldValue = useContextSelector(
RecordFieldValueSelectorContext,
(value) => value[0]?.[recordId]?.[fieldName],
const recordFieldValue = useRecoilValue(
recordStoreFamilySelector({
recordId,
fieldName,
}),
);
return recordFieldValue as T | undefined;
};
export const useSetRecordFieldValue = () => {
const setTableValue = useContextSelector(
RecordFieldValueSelectorContext,
(value) => value[1],
);
return (recordId: string, fieldName: string, newValue: any) => {
setTableValue((currentTable) => ({
...currentTable,
[recordId]: {
...currentTable[recordId],
[fieldName]: newValue,
},
}));
};
};
export const RecordFieldValueSelectorContextProvider = ({
children,
}: {
children: any;
}) => (
<RecordFieldValueSelectorContext.Provider
value={useState<RecordFieldValue>({})}
>
{children}
</RecordFieldValueSelectorContext.Provider>
);

View File

@ -6,10 +6,6 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import {
RecordFieldValueSelectorContextProvider,
useSetRecordValue,
} from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
@ -36,22 +32,14 @@ const RelationFieldValueSetterEffect = () => {
recordStoreFamilyState(mockPerformance.relationRecordId),
);
const setRecordValue = useSetRecordValue();
const [, setObjectMetadataItems] = useRecoilState(objectMetadataItemsState);
useEffect(() => {
setEntity(mockPerformance.entityValue);
setRelationEntity(mockPerformance.relationFieldValue);
setRecordValue(mockPerformance.entityValue.id, mockPerformance.entityValue);
setRecordValue(
mockPerformance.relationFieldValue.id,
mockPerformance.relationFieldValue,
);
setObjectMetadataItems(generatedMockObjectMetadataItems);
}, [setEntity, setRelationEntity, setRecordValue, setObjectMetadataItems]);
}, [setEntity, setRelationEntity, setObjectMetadataItems]);
return null;
};
@ -63,95 +51,93 @@ const meta: Meta = {
ChipGeneratorsDecorator,
(Story) => {
return (
<RecordFieldValueSelectorContextProvider>
<RecordIndexContextProvider
<RecordIndexContextProvider
value={{
indexIdentifierUrl: (_recordId: string) => '',
onIndexRecordsLoaded: () => {},
objectNamePlural: 'companies',
objectNameSingular: 'company',
objectMetadataItem: mockPerformance.objectMetadataItem as any,
recordIndexId: 'recordIndexId',
}}
>
<RecordTableContextProvider
value={{
indexIdentifierUrl: (_recordId: string) => '',
onIndexRecordsLoaded: () => {},
objectNamePlural: 'companies',
objectNameSingular: 'company',
recordTableId: 'recordTableId',
viewBarId: mockPerformance.recordId,
objectMetadataItem: mockPerformance.objectMetadataItem as any,
recordIndexId: 'recordIndexId',
visibleTableColumns: mockPerformance.visibleTableColumns as any,
objectNameSingular:
mockPerformance.objectMetadataItem.nameSingular,
}}
>
<RecordTableContextProvider
value={{
recordTableId: 'recordTableId',
viewBarId: mockPerformance.recordId,
objectMetadataItem: mockPerformance.objectMetadataItem as any,
visibleTableColumns: mockPerformance.visibleTableColumns as any,
objectNameSingular:
mockPerformance.objectMetadataItem.nameSingular,
}}
<RecordTableComponentInstance
recordTableId="asd"
onColumnsChange={() => {}}
>
<RecordTableComponentInstance
recordTableId="asd"
onColumnsChange={() => {}}
<RecordTableBodyContextProvider
value={{
onOpenTableCell: () => {},
onMoveFocus: () => {},
onCloseTableCell: () => {},
onMoveHoverToCurrentCell: () => {},
onActionMenuDropdownOpened: () => {},
onCellMouseEnter: () => {},
}}
>
<RecordTableBodyContextProvider
<RecordTableRowContextProvider
value={{
onOpenTableCell: () => {},
onMoveFocus: () => {},
onCloseTableCell: () => {},
onMoveHoverToCurrentCell: () => {},
onActionMenuDropdownOpened: () => {},
onCellMouseEnter: () => {},
objectNameSingular:
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
recordId: mockPerformance.recordId,
rowIndex: 0,
pathToShowPage:
getBasePathToShowPage({
objectNameSingular:
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
}) + mockPerformance.recordId,
isSelected: false,
inView: true,
}}
>
<RecordTableRowContextProvider
<RecordTableRowDraggableContextProvider
value={{
objectNameSingular:
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
recordId: mockPerformance.recordId,
rowIndex: 0,
pathToShowPage:
getBasePathToShowPage({
objectNameSingular:
mockPerformance.entityValue.__typename.toLocaleLowerCase(),
}) + mockPerformance.recordId,
isSelected: false,
inView: true,
isDragging: false,
dragHandleProps: null,
}}
>
<RecordTableRowDraggableContextProvider
<RecordTableCellContext.Provider
value={{
isDragging: false,
dragHandleProps: null,
columnDefinition: mockPerformance.fieldDefinition,
cellPosition: { row: 0, column: 0 },
}}
>
<RecordTableCellContext.Provider
<FieldContext.Provider
value={{
columnDefinition: mockPerformance.fieldDefinition,
cellPosition: { row: 0, column: 0 },
recordId: mockPerformance.recordId,
isLabelIdentifier: false,
fieldDefinition: {
...mockPerformance.fieldDefinition,
},
isReadOnly: false,
}}
>
<FieldContext.Provider
value={{
recordId: mockPerformance.recordId,
isLabelIdentifier: false,
fieldDefinition: {
...mockPerformance.fieldDefinition,
},
isReadOnly: false,
}}
>
<RelationFieldValueSetterEffect />
<table>
<tbody>
<tr>
<Story />
</tr>
</tbody>
</table>
</FieldContext.Provider>
</RecordTableCellContext.Provider>
</RecordTableRowDraggableContextProvider>
</RecordTableRowContextProvider>
</RecordTableBodyContextProvider>
</RecordTableComponentInstance>
</RecordTableContextProvider>
</RecordIndexContextProvider>
</RecordFieldValueSelectorContextProvider>
<RelationFieldValueSetterEffect />
<table>
<tbody>
<tr>
<Story />
</tr>
</tbody>
</table>
</FieldContext.Provider>
</RecordTableCellContext.Provider>
</RecordTableRowDraggableContextProvider>
</RecordTableRowContextProvider>
</RecordTableBodyContextProvider>
</RecordTableComponentInstance>
</RecordTableContextProvider>
</RecordIndexContextProvider>
);
},
ComponentDecorator,

View File

@ -2,7 +2,7 @@ import { useRecoilCallback } from 'recoil';
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { useSetRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useSetIsRecordTableFocusActive } from '@/object-record/record-table/record-table-cell/hooks/useSetIsRecordTableFocusActive';
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
@ -27,8 +27,6 @@ export const useSetRecordTableData = ({
recordTableId,
onEntityCountChange,
}: useSetRecordTableDataProps) => {
const setRecordValueInContextSelector = useSetRecordValue();
const recordIndexRecordIdsByGroupFamilyState =
useRecoilComponentCallbackStateV2(
recordIndexRecordIdsByGroupComponentFamilyState,
@ -82,7 +80,6 @@ export const useSetRecordTableData = ({
};
set(recordStoreFamilyState(record.id), newRecord);
setRecordValueInContextSelector(record.id, newRecord);
}
}
@ -130,7 +127,6 @@ export const useSetRecordTableData = ({
setRecordTableHoverPosition,
onEntityCountChange,
isRowSelectedFamilyState,
setRecordValueInContextSelector,
],
);
};

View File

@ -1,12 +1,13 @@
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
import { INLINE_CELL_HOTKEY_SCOPE_MEMOIZE_KEY } from '@/object-record/record-inline-cell/constants/InlineCellHotkeyScopeMemoizeKey';
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
import { useRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { Theme, withTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { OverflowingTextWithTooltip } from 'twenty-ui/display';
const StyledDiv = styled.div`
@ -33,7 +34,9 @@ const StyledEmptyText = withTheme(styled.div<{ theme: Theme }>`
export const RecordTitleCellSingleTextDisplayMode = () => {
const { recordId, fieldDefinition } = useContext(FieldContext);
const recordValue = useRecordValue(recordId);
const recordValue = useRecoilValue(recordStoreFamilyState(recordId));
const isEmpty =
recordValue?.[fieldDefinition.metadata.fieldName]?.trim() === '';