Keep unchanged metadata stable for memoization
Everytime the metadata got updated, unchanged values could cause rerenders because their reference changed. This happened e.g., for the "customThemes" which caused the MUI theme to get recreated resulting in all components to rerender due to the theme context change.
This commit is contained in:
@@ -23,6 +23,48 @@ import { applyMetadataMigrations } from '@/features/metadata/services/MetadataMi
|
||||
import { SourceIdInfo } from '@/features/source/Source.types.ts';
|
||||
import { ChapterIdInfo } from '@/features/chapter/Chapter.types.ts';
|
||||
import { APP_METADATA } from '@/features/metadata/Metadata.constants.ts';
|
||||
import { MetadataValueCache } from '@/features/metadata/services/MetadataValueCache.ts';
|
||||
|
||||
const getHolderId = (
|
||||
type: MetadataHolderType,
|
||||
metadataHolder:
|
||||
| MetadataHolder
|
||||
| (MangaIdInfo & MetadataHolder)
|
||||
| (ChapterIdInfo & MetadataHolder)
|
||||
| (CategoryIdInfo & MetadataHolder)
|
||||
| (SourceIdInfo & MetadataHolder),
|
||||
): string | number | undefined => {
|
||||
switch (type) {
|
||||
case 'global':
|
||||
return undefined;
|
||||
case 'manga':
|
||||
return (metadataHolder as MangaIdInfo).id;
|
||||
case 'chapter':
|
||||
return (metadataHolder as ChapterIdInfo).id;
|
||||
case 'category':
|
||||
return (metadataHolder as CategoryIdInfo).id;
|
||||
case 'source':
|
||||
return (metadataHolder as SourceIdInfo).id;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const getRawMetadataValueFrom = (
|
||||
metadata: Metadata | undefined,
|
||||
key: string,
|
||||
prefixes?: string[],
|
||||
): string | undefined => {
|
||||
if (
|
||||
metadata === undefined ||
|
||||
!doesMetadataKeyExistIn(metadata, key, prefixes) ||
|
||||
metadata[getMetadataKey(key, prefixes)] === undefined
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return metadata[getMetadataKey(key, prefixes)];
|
||||
};
|
||||
|
||||
const getMetadataValueFrom = <Key extends AppMetadataKeys, Value extends AllowedMetadataValueTypes>(
|
||||
metadata: Metadata | undefined,
|
||||
@@ -30,15 +72,13 @@ const getMetadataValueFrom = <Key extends AppMetadataKeys, Value extends Allowed
|
||||
defaultValue?: Value,
|
||||
prefixes?: string[],
|
||||
): Value | undefined => {
|
||||
if (
|
||||
metadata === undefined ||
|
||||
!doesMetadataKeyExistIn(metadata, key, prefixes) ||
|
||||
metadata[getMetadataKey(key, prefixes)] === undefined
|
||||
) {
|
||||
const rawValue = getRawMetadataValueFrom(metadata, key, prefixes);
|
||||
|
||||
if (rawValue === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
const convertedValue = convertValueFromMetadata(key, metadata[getMetadataKey(key, prefixes)], defaultValue);
|
||||
const convertedValue = convertValueFromMetadata(key, rawValue, defaultValue);
|
||||
|
||||
return APP_METADATA[key].toConstrainedValue?.(convertedValue) ?? convertedValue;
|
||||
};
|
||||
@@ -92,13 +132,18 @@ export function getMetadataFrom<METADATA extends Partial<Metadata<AppMetadataKey
|
||||
): METADATA {
|
||||
const migratedMetadata = applyMetadataMigrations(type, metadataHolder, useEffectFn);
|
||||
const appMetadata = {} as METADATA;
|
||||
const holderId = getHolderId(type, metadataHolder);
|
||||
|
||||
Object.entries(metadataWithDefaultValues).forEach(([key, defaultValue]) => {
|
||||
appMetadata[key as AppMetadataKeys] = getMetadataValueFrom(
|
||||
migratedMetadata,
|
||||
key as AppMetadataKeys,
|
||||
defaultValue,
|
||||
prefixes,
|
||||
const rawValue = getRawMetadataValueFrom(migratedMetadata, key as AppMetadataKeys, prefixes);
|
||||
const newValue = getMetadataValueFrom(migratedMetadata, key as AppMetadataKeys, defaultValue, prefixes);
|
||||
|
||||
appMetadata[key as AppMetadataKeys] = MetadataValueCache.getStableValue(
|
||||
type,
|
||||
holderId,
|
||||
getMetadataKey(key, prefixes),
|
||||
rawValue,
|
||||
newValue,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user