Skip to content

Commit

Permalink
Update popup when props change in usePopup
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexShukel committed Sep 3, 2023
1 parent e7e08cf commit 843d8e3
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 26 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
"lint": "aqu lint",
"lint:fix": "aqu lint --fix",
"test": "aqu test",
"test:watch": "npm test -- --watch",
"test:coverage": "npm test -- --coverage --json --silent --ci --outputFile=\"report.json\"",
"test:log-coverage": "npm test -- --coverage --silent --ci --coverageReporters=text",
"test:watch": "pnpm test -- --watch",
"test:coverage": "pnpm test -- --coverage --json --silent --ci --outputFile=\"report.json\"",
"test:log-coverage": "pnpm test -- --coverage --silent --ci --coverageReporters=text",
"release": "np",
"prepublishOnly": "aqu build"
},
Expand Down
16 changes: 10 additions & 6 deletions src/hooks/usePopup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ComponentType, useCallback, useRef } from 'react';
import { ComponentType, useCallback, useEffect, useRef } from 'react';
import { nanoid } from 'nanoid/non-secure';

import { useEvent } from './useEvent';
Expand All @@ -10,15 +10,15 @@ import { PopupIdentifier } from '../types/PopupIdentifier';

export type UsePopupBag<P, K extends keyof P> = [
open: OptionalParamFunction<Omit<P, K>, void>,
close: () => void
close: () => void,

Check failure on line 13 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 13 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
];

export const usePopup = <P, K extends keyof P>(
PopupComponent: ComponentType<P>,
props: Pick<P, K>,
group: PopupGroup
group: PopupGroup,

Check failure on line 19 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 19 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
): UsePopupBag<P, K> => {
const { mount, close: closePopup, unmount } = usePopupsContext();
const { mount, close: closePopup, unmount, update } = usePopupsContext();

const popupIdentifier = useRef<PopupIdentifier>({
id: nanoid(),
Expand All @@ -35,16 +35,20 @@ export const usePopup = <P, K extends keyof P>(
PopupComponent as ComponentType<{}>,
{ ...props, ...omittedProps },
popupIdentifier.current,
defaultClose
defaultClose,

Check failure on line 38 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 38 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
);

mount(popup);
}
},

Check failure on line 42 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 42 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
);

const close = useCallback(() => {
closePopup(popupIdentifier.current);
}, [closePopup]);

useEffect(() => {
update(popupIdentifier.current, props);
}, [props]);

Check warning on line 51 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

React Hook useEffect has a missing dependency: 'update'. Either include it or remove the dependency array

Check warning on line 51 in src/hooks/usePopup.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

React Hook useEffect has a missing dependency: 'update'. Either include it or remove the dependency array

return [open, close];
};
16 changes: 15 additions & 1 deletion src/hooks/usePopupsBag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,31 @@ export const usePopupsBag = (): PopupsBag => {
return popup.popupIdentifier;
}, []);

const update = useCallback(
(popupIdentifier: PopupIdentifier, props: object) => {
dispatch({
type: ActionType.UPDATE,
payload: {
popupIdentifier,
props,
},
});
},
[],

Check failure on line 49 in src/hooks/usePopupsBag.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 49 in src/hooks/usePopupsBag.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
);

const close = useCallback(
(popupIdentifier: PopupIdentifier) => {
const popup = getPopup(popupIdentifier);
popup?.close();
},
[getPopup]
[getPopup],

Check failure on line 57 in src/hooks/usePopupsBag.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 57 in src/hooks/usePopupsBag.ts

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
);

return {
mount,
unmount,
update,
getPopup,
close,
popupsState,
Expand Down
1 change: 1 addition & 0 deletions src/types/PopupsBag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PopupsState } from '../utils/popupsReducer';
export type PopupsBag = {
mount: <P>(popup: Popup<P>) => PopupIdentifier;
unmount: (popupIdentifier: PopupIdentifier) => void;
update: (popupIdentifier: PopupIdentifier, props: object) => void;
close: (popupIdentifier: PopupIdentifier) => void;

popupsState: PopupsState;
Expand Down
34 changes: 29 additions & 5 deletions src/utils/popupsReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PopupsRegistry } from '../types/PopupsRegistry';
export enum ActionType {
MOUNT,
UNMOUNT,
UPDATE,
}

type MountAction = {
Expand All @@ -21,14 +22,21 @@ type UnmountAction = {
};
};

export type PopupsAction = MountAction | UnmountAction;
type UpdateAction = {
type: ActionType.UPDATE;
payload: {
popupIdentifier: PopupIdentifier;
props: object;
};
};

export type PopupsAction = MountAction | UnmountAction | UpdateAction;

export type PopupsState = { popups: PopupsRegistry };

export const popupsReducer = (
{ popups }: PopupsState,
action: PopupsAction
) => {
export const popupsReducer = (prevState: PopupsState, action: PopupsAction) => {
const { popups } = prevState;

switch (action.type) {
case ActionType.MOUNT: {
const { popup } = action.payload;
Expand All @@ -47,6 +55,22 @@ export const popupsReducer = (
};
}

case ActionType.UPDATE: {
const { popupIdentifier, props } = action.payload;

const { groupId, id } = popupIdentifier;

if (!popups[groupId]?.[id]) {
return prevState;
}

popups[groupId][id].props = props;

return {
popups,
};
}

case ActionType.UNMOUNT: {
const { groupId, id } = action.payload.popupIdentifier;

Expand Down
51 changes: 40 additions & 11 deletions test/hooks/usePopup.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const SimplePopupComponent: React.FC = jest.fn(() => {
});

const CustomizablePopupComponent: React.FC<{ message: string }> = jest.fn(
({ message }) => <div>{message}</div>
({ message }) => <div>{message}</div>,

Check failure on line 17 in test/hooks/usePopup.test.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 17 in test/hooks/usePopup.test.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
);

const PopupComponentWithProps: React.FC<{
Expand All @@ -24,11 +24,12 @@ const PopupComponentWithProps: React.FC<{

describe('usePopup', () => {
it('should render only one popup', () => {
const initialProps = {};
const { result } = renderHook(
() => usePopup(SimplePopupComponent, {}, group),
() => usePopup(SimplePopupComponent, initialProps, group),
{
wrapper: TestHookWrapper,
}
},

Check failure on line 32 in test/hooks/usePopup.test.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 32 in test/hooks/usePopup.test.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
);

act(() => {
Expand All @@ -45,11 +46,12 @@ describe('usePopup', () => {
});

it('should close popup', () => {
const initialProps = {};
const { result } = renderHook(
() => usePopup(SimplePopupComponent, {}, group),
() => usePopup(SimplePopupComponent, initialProps, group),
{
wrapper: TestHookWrapper,
}
},

Check failure on line 54 in test/hooks/usePopup.test.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 54 in test/hooks/usePopup.test.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
);

act(() => {
Expand All @@ -65,13 +67,14 @@ describe('usePopup', () => {
expect(() => screen.getByText('simple popup')).toThrow();
});

it('should update popup', () => {
it('should reopen popup with new props', () => {
const initialMessage = 'initial message';
const updatedMessage = 'updated message';

const initialProps = {};
const { result } = renderHook(
() => usePopup(CustomizablePopupComponent, {}, group),
{ wrapper: TestHookWrapper }
() => usePopup(CustomizablePopupComponent, initialProps, group),
{ wrapper: TestHookWrapper },

Check failure on line 77 in test/hooks/usePopup.test.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

Delete `,`

Check failure on line 77 in test/hooks/usePopup.test.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 18.x and ubuntu-latest

Delete `,`
);

act(() => {
Expand All @@ -90,22 +93,48 @@ describe('usePopup', () => {
});

it('should merge props', () => {
const initialProps = { prop1: 42 };
const { result } = renderHook(
() => usePopup(PopupComponentWithProps, { prop1: 42 }, group),
() => usePopup(PopupComponentWithProps, initialProps, group),
{
wrapper: TestHookWrapper,
}
},
);

act(() => {
result.current[0]({ prop2: 'hello' });
});

expect(
(PopupComponentWithProps as jest.Mock).mock.calls[0][0]
(PopupComponentWithProps as jest.Mock).mock.calls[0][0],
).toStrictEqual({
prop1: 42,
prop2: 'hello',
});
});

it('should update popup when props changing', () => {
const { result, rerender } = renderHook(
(props: { message: string }) =>
usePopup(CustomizablePopupComponent, props, group),
{
wrapper: TestHookWrapper,
initialProps: {
message: 'initial',
},
},
);

act(() => {
result.current[0]();
});

expect(screen.getByText('initial')).toBeDefined();

rerender({
message: 'updated',
});

expect(screen.getByText('updated')).toBeDefined();
});
});

0 comments on commit 843d8e3

Please sign in to comment.