Skip to content

Commit

Permalink
fix: clean up data when each subscriber has unmounted (when using `id…
Browse files Browse the repository at this point in the history
…` to sync components with each other)
  • Loading branch information
tujoworker committed Dec 13, 2024
1 parent 56d4956 commit 21db4d5
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ describe('useSharedState', () => {
const { result } = renderHook(() =>
useSharedState(identifier, { test: 'initial' })
)
const sharedState = createSharedState(identifier, {
test: 'initial',
})
const sharedState = createSharedState(identifier)
act(() => {
sharedState.update({ test: 'changed' })
})
Expand Down Expand Up @@ -101,16 +99,41 @@ describe('useSharedState', () => {
const { result, unmount } = renderHook(() =>
useSharedState(identifier, { test: 'initial' })
)
const sharedState = createSharedState(identifier, {
test: 'initial',
})
const sharedState = createSharedState(identifier)

unmount()

act(() => {
sharedState.update({ test: 'unmounted' })
})

expect(result.current.data).toEqual({ test: 'initial' })
})

it('should delete the shared state when all components have been unmounted', () => {
const identifier = {}

const { unmount: unmountA } = renderHook(() =>
useSharedState(identifier, { test: 'initial' })
)
const { unmount: unmountB } = renderHook(() =>
useSharedState(identifier)
)

const getStateOf = (identifier) => {
return createSharedState(identifier).get()
}

expect(getStateOf(identifier)).toEqual({ test: 'initial' })
expect(getStateOf(identifier)).toEqual({ test: 'initial' })

unmountA()
unmountB()

expect(getStateOf(identifier)).toEqual(undefined)
expect(getStateOf(identifier)).toEqual(undefined)
})

it('should return undefined data when no ID is given', () => {
const { result } = renderHook(() =>
useSharedState(null, { test: 'initial' })
Expand Down
23 changes: 17 additions & 6 deletions packages/dnb-eufemia/src/shared/helpers/useSharedState.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ export function useSharedState<Data>(

return () => {
sharedState.unsubscribe(forceRerender)

if (sharedState.subscribersRef.current.length === 0) {
sharedState.update(undefined)
}
}
}, [forceRerender, id, onChange, sharedState])

Expand Down Expand Up @@ -153,6 +157,7 @@ export interface SharedStateReturn<Data = undefined> {
set: (newData: Partial<Data>) => void
extend: (newData: Partial<Data>, opts?: Options) => void
update: (newData: Partial<Data>, opts?: Options) => void
subscribersRef: { current: Subscriber[] }
}

interface SharedStateInstance<Data> extends SharedStateReturn<Data> {
Expand Down Expand Up @@ -185,10 +190,12 @@ export function createSharedState<Data>(
} = {}
): SharedStateInstance<Data> {
if (!sharedStates.get(id)) {
let subscribers: Subscriber[] = []
const subscribersRef = {
current: [] as Subscriber[],
}

const sync = (opts: Options = {}) => {
subscribers.forEach((subscriber) => {
subscribersRef.current.forEach((subscriber) => {
const syncNow = opts.preventSyncOfSameInstance
? shouldSync?.(subscriber) !== false
: true
Expand All @@ -201,7 +208,8 @@ export function createSharedState<Data>(
const get = () => sharedStates.get(id).data

const set = (newData: Partial<Data>) => {
sharedStates.get(id).data = { ...newData }
sharedStates.get(id).data =
newData === undefined ? undefined : { ...newData }
}

const update = (newData: Partial<Data>, opts?: Options) => {
Expand All @@ -218,13 +226,15 @@ export function createSharedState<Data>(
}

const subscribe = (subscriber: Subscriber) => {
if (!subscribers.includes(subscriber)) {
subscribers.push(subscriber)
if (!subscribersRef.current.includes(subscriber)) {
subscribersRef.current.push(subscriber)
}
}

const unsubscribe = (subscriber: Subscriber) => {
subscribers = subscribers.filter((sub) => sub !== subscriber)
subscribersRef.current = subscribersRef.current.filter(
(sub) => sub !== subscriber
)
}

sharedStates.set(id, {
Expand All @@ -236,6 +246,7 @@ export function createSharedState<Data>(
subscribe,
unsubscribe,
hadInitialData: Boolean(initialData),
subscribersRef,
} as SharedStateInstance<Data>)

if (initialData) {
Expand Down

0 comments on commit 21db4d5

Please sign in to comment.