Skip to content

Instantly share code, notes, and snippets.

@karol-majewski
Last active May 17, 2024 22:16
Show Gist options
  • Save karol-majewski/3ceb43ccfe0075e2d9ef7c7247e384d3 to your computer and use it in GitHub Desktop.
Save karol-majewski/3ceb43ccfe0075e2d9ef7c7247e384d3 to your computer and use it in GitHub Desktop.
import React from 'react';
import createPersistedState from 'use-persisted-state';
import { storage } from '../utilities/storage';
import { hasElements, head, isDefined } from '@rhim/utils';
const usePersistedEntityId = createPersistedState('some-entity-key', storage);
interface Entity {
id: UUID;
}
type Persistable = UUID | null;
/**
* @param entities The domain of possible values to select from
* @param initialValue A preferred initial value. Example use: obtain it from `URLSearchParams`
*/
export function useSelectedEntityId(entities: Entity[], initialValue?: UUID): Persistable {
const [persistedEntityId, setPersistedEntityId] = usePersistedEntityId<Persistable>(initialValue ?? null);
const strategy = React.useCallback((entities: Entity[], persistedEntityId: Persistable): Persistable => {
const preferredEntity: Entity | undefined = entities.find((entity) => entity.id === persistedEntityId);
// True when the persisted entity ID matches the available entities. This is not always the case.
// For example, the entities might change in the meantime and so the persisted ID is outside the domain.
const hasPreferredEntity = isDefined(preferredEntity);
if (hasPreferredEntity) {
return preferredEntity.id;
} else if (hasElements(entities)) {
return head(entities).id;
} else {
return null;
}
}, []);
const currentValue = React.useMemo(() => {
return strategy(entities, persistedEntityId);
}, [entities, persistedEntityId, strategy]);
React.useEffect(() => {
const nextValue = strategy(entities, persistedEntityId);
if (currentValue !== nextValue) {
setPersistedEntityId(nextValue);
}
}, [currentValue, entities, persistedEntityId, setPersistedEntityId, strategy])
return currentValue;
}
import React from 'react';
import createPersistedState from 'use-persisted-state';
import { storage } from '../utilities/storage';
import { hasElements, head, isDefined } from '@rhim/utils';
const usePersistedEntityId = createPersistedState('some-entity-key', storage);
interface Entity {
id: UUID;
}
/**
* @param entities The domain of possible values to select from
* @param initialValue A preferred initial value. Example use: obtain it from `URLSearchParams`
*/
export function useSelectedEntityId(entities: Entity[], initialValue?: UUID) {
const [persistedEntityId, setPersistedEntityId] = usePersistedEntityId<UUID | null>(initialValue ?? null);
// This is the value we're going to return. It's computed based on the persisted preference and the domain of available entities.
const entityId = React.useMemo(() => {
const preferredEntity: Entity | undefined = entities.find((entity) => entity.id === persistedEntityId);
// True when the persisted entity ID matches the available entities. This is not always the case.
// For example, the entities might change in the meantime and so the persisted ID is outside the domain.
const hasPreferredEntity = isDefined(preferredEntity);
if (hasPreferredEntity) {
return preferredEntity.id;
} else if (hasElements(entities)) {
return head(entities).id;
} else {
return null;
}
}, [entities, persistedEntityId]);
// Whenever either `entities` or `persistedEntityId` change, apply the same logic and persist the new value.
React.useEffect(() => {
const preferredEntity: Entity | undefined = entities.find((entity) => entity.id === persistedEntityId);
const hasPreferredEntity = isDefined(preferredEntity);
if (hasPreferredEntity) {
return;
} else if (hasElements(entities)) {
setPersistedEntityId(head(entities).id);
} else {
setPersistedEntityId(null);
}
}, [persistedEntityId, setPersistedEntityId, entities]);
return React.useMemo(() => {
return [entityId, setPersistedEntityId];
}, [entityId, setPersistedEntityId]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment