Skip to content

Commit 4f2a011

Browse files
Add support for React strict mode
1 parent 0c9f939 commit 4f2a011

File tree

12 files changed

+120
-54
lines changed

12 files changed

+120
-54
lines changed

src/components/content-presentation/notification-banner/NotificationBanner.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
import {
44
Children,
5-
createRef,
65
forwardRef,
76
useEffect,
7+
useImperativeHandle,
8+
useRef,
89
useState,
910
type ComponentPropsWithoutRef,
1011
} from 'react';
@@ -27,19 +28,22 @@ const NotificationBannerComponent = forwardRef<HTMLDivElement, NotificationBanne
2728
(props, forwardedRef) => {
2829
const { children, className, title, titleId, success, role, disableAutoFocus, ...rest } = props;
2930

30-
const [moduleRef] = useState(() => forwardedRef || createRef<HTMLDivElement>());
31+
const moduleRef = useRef<HTMLDivElement>(null);
32+
const importRef = useRef<Promise<NotificationBannerModule | void>>(null);
3133
const [instanceError, setInstanceError] = useState<Error>();
3234
const [instance, setInstance] = useState<NotificationBannerModule>();
3335

36+
useImperativeHandle(forwardedRef, () => moduleRef.current!, [moduleRef]);
37+
3438
useEffect(() => {
35-
if (!('current' in moduleRef) || !moduleRef.current || instance) {
39+
if (!moduleRef.current || importRef.current || instance) {
3640
return;
3741
}
3842

39-
import('nhsuk-frontend')
43+
importRef.current = import('nhsuk-frontend')
4044
.then(({ NotificationBanner }) => setInstance(new NotificationBanner(moduleRef.current)))
4145
.catch(setInstanceError);
42-
}, [moduleRef, instance]);
46+
}, [moduleRef, importRef, instance]);
4347

4448
const items = Children.toArray(children);
4549

src/components/content-presentation/table/components/__tests__/TableCell.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ describe('Table.Cell', () => {
2929
</table>,
3030
);
3131

32-
expect(console.warn).toHaveBeenCalledTimes(1);
32+
expect(console.warn).toHaveBeenCalled();
3333
expect(console.warn).toHaveBeenLastCalledWith(
3434
'Table.Cell used outside of a Table.Head or Table.Body component. Unable to determine section type from context.',
3535
);

src/components/content-presentation/tabs/Tabs.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
import classNames from 'classnames';
44
import { type Tabs as TabsModule } from 'nhsuk-frontend';
55
import {
6-
createRef,
76
forwardRef,
87
useEffect,
8+
useImperativeHandle,
9+
useRef,
910
useState,
1011
type ComponentPropsWithoutRef,
1112
type FC,
@@ -55,19 +56,22 @@ export const TabsContents: FC<TabsContentsProps> = ({ children, id, ...rest }) =
5556
const TabsComponent = forwardRef<HTMLDivElement, TabsProps>((props, forwardedRef) => {
5657
const { children, className, ...rest } = props;
5758

58-
const [moduleRef] = useState(() => forwardedRef || createRef<HTMLDivElement>());
59+
const moduleRef = useRef<HTMLDivElement>(null);
60+
const importRef = useRef<Promise<TabsModule | void>>(null);
5961
const [instanceError, setInstanceError] = useState<Error>();
6062
const [instance, setInstance] = useState<TabsModule>();
6163

64+
useImperativeHandle(forwardedRef, () => moduleRef.current!, [moduleRef]);
65+
6266
useEffect(() => {
63-
if (!('current' in moduleRef) || !moduleRef.current || instance) {
67+
if (!moduleRef.current || importRef.current || instance) {
6468
return;
6569
}
6670

67-
import('nhsuk-frontend')
71+
importRef.current = import('nhsuk-frontend')
6872
.then(({ Tabs }) => setInstance(new Tabs(moduleRef.current)))
6973
.catch(setInstanceError);
70-
}, [moduleRef, instance]);
74+
}, [moduleRef, importRef, instance]);
7175

7276
if (instanceError) {
7377
throw instanceError;

src/components/form-elements/button/Button.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
import classNames from 'classnames';
44
import { type Button as ButtonModule } from 'nhsuk-frontend';
55
import {
6-
createRef,
76
forwardRef,
87
useEffect,
8+
useImperativeHandle,
9+
useRef,
910
useState,
1011
type ForwardedRef,
1112
type MouseEvent,
@@ -45,19 +46,22 @@ const ButtonComponent = forwardRef<HTMLButtonElement, ButtonProps>((props, forwa
4546
...rest
4647
} = props;
4748

48-
const [moduleRef] = useState(() => forwardedRef || createRef<HTMLButtonElement>());
49+
const moduleRef = useRef<HTMLButtonElement>(null);
50+
const importRef = useRef<Promise<ButtonModule | void>>(null);
4951
const [instanceError, setInstanceError] = useState<Error>();
5052
const [instance, setInstance] = useState<ButtonModule>();
5153

54+
useImperativeHandle(forwardedRef, () => moduleRef.current!, [moduleRef]);
55+
5256
useEffect(() => {
53-
if (!('current' in moduleRef) || !moduleRef.current || instance) {
57+
if (!moduleRef.current || importRef.current || instance) {
5458
return;
5559
}
5660

57-
import('nhsuk-frontend')
61+
importRef.current = import('nhsuk-frontend')
5862
.then(({ Button }) => setInstance(new Button(moduleRef.current)))
5963
.catch(setInstanceError);
60-
}, [moduleRef, instance]);
64+
}, [moduleRef, importRef, instance]);
6165

6266
if (instanceError) {
6367
throw instanceError;
@@ -104,19 +108,22 @@ const ButtonLinkComponent = forwardRef<HTMLAnchorElement, ButtonLinkProps>(
104108
...rest
105109
} = props;
106110

107-
const [moduleRef] = useState(() => forwardedRef || createRef<HTMLAnchorElement>());
111+
const moduleRef = useRef<HTMLAnchorElement>(null);
112+
const importRef = useRef<Promise<ButtonModule | void>>(null);
108113
const [instanceError, setInstanceError] = useState<Error>();
109114
const [instance, setInstance] = useState<ButtonModule>();
110115

116+
useImperativeHandle(forwardedRef, () => moduleRef.current!, [moduleRef]);
117+
111118
useEffect(() => {
112-
if (!('current' in moduleRef) || !moduleRef.current || instance) {
119+
if (!moduleRef.current || importRef.current || instance) {
113120
return;
114121
}
115122

116-
import('nhsuk-frontend')
123+
importRef.current = import('nhsuk-frontend')
117124
.then(({ Button }) => setInstance(new Button(moduleRef.current)))
118125
.catch(setInstanceError);
119-
}, [moduleRef, instance]);
126+
}, [moduleRef, importRef, instance]);
120127

121128
if (instanceError) {
122129
throw instanceError;

src/components/form-elements/character-count/CharacterCount.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22

33
import classNames from 'classnames';
44
import { type CharacterCount as CharacterCountModule } from 'nhsuk-frontend';
5-
import { createRef, forwardRef, useEffect, useState, type ComponentPropsWithoutRef } from 'react';
5+
import {
6+
forwardRef,
7+
useEffect,
8+
useImperativeHandle,
9+
useRef,
10+
useState,
11+
type ComponentPropsWithoutRef,
12+
} from 'react';
613
import { FormGroup } from '#components/utils/index.js';
714
import { type FormElementProps } from '#util/types/FormTypes.js';
815

@@ -16,19 +23,22 @@ export interface CharacterCountProps
1623

1724
export const CharacterCount = forwardRef<HTMLTextAreaElement, CharacterCountProps>(
1825
({ maxLength, maxWords, threshold, formGroupProps, ...rest }, forwardedRef) => {
19-
const [moduleRef] = useState(() => formGroupProps?.ref || createRef<HTMLDivElement>());
26+
const moduleRef = useRef<HTMLDivElement>(null);
27+
const importRef = useRef<Promise<CharacterCountModule | void>>(null);
2028
const [instanceError, setInstanceError] = useState<Error>();
2129
const [instance, setInstance] = useState<CharacterCountModule>();
2230

31+
useImperativeHandle(formGroupProps?.ref, () => moduleRef.current!, [moduleRef]);
32+
2333
useEffect(() => {
24-
if (!('current' in moduleRef) || !moduleRef.current || instance) {
34+
if (!moduleRef.current || importRef.current || instance) {
2535
return;
2636
}
2737

28-
import('nhsuk-frontend')
38+
importRef.current = import('nhsuk-frontend')
2939
.then(({ CharacterCount }) => setInstance(new CharacterCount(moduleRef.current)))
3040
.catch(setInstanceError);
31-
}, [moduleRef, instance]);
41+
}, [moduleRef, importRef, instance]);
3242

3343
if (instanceError) {
3444
throw instanceError;

src/components/form-elements/checkboxes/Checkboxes.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22

33
import classNames from 'classnames';
44
import { type Checkboxes as CheckboxesModule } from 'nhsuk-frontend';
5-
import { createRef, forwardRef, useEffect, useState, type ComponentPropsWithoutRef } from 'react';
5+
import {
6+
forwardRef,
7+
useEffect,
8+
useImperativeHandle,
9+
useRef,
10+
useState,
11+
type ComponentPropsWithoutRef,
12+
} from 'react';
613
import { CheckboxesDivider, CheckboxesItem } from './components/index.js';
714
import { CheckboxesContext, type ICheckboxesContext } from './CheckboxesContext.js';
815
import { FormGroup } from '#components/utils/index.js';
@@ -19,23 +26,26 @@ export interface CheckboxesProps
1926
const CheckboxesComponent = forwardRef<HTMLDivElement, CheckboxesProps>((props, forwardedRef) => {
2027
const { children, idPrefix, ...rest } = props;
2128

22-
const [moduleRef] = useState(() => forwardedRef || createRef<HTMLDivElement>());
29+
const moduleRef = useRef<HTMLDivElement>(null);
30+
const importRef = useRef<Promise<CheckboxesModule | void>>(null);
2331
const [instanceError, setInstanceError] = useState<Error>();
2432
const [instance, setInstance] = useState<CheckboxesModule>();
2533

2634
const _boxReferences: string[] = [];
2735
let _boxCount: number = 0;
2836
let _boxIds: Record<string, string> = {};
2937

38+
useImperativeHandle(forwardedRef, () => moduleRef.current!, [moduleRef]);
39+
3040
useEffect(() => {
31-
if (!('current' in moduleRef) || !moduleRef.current || instance) {
41+
if (!moduleRef.current || importRef.current || instance) {
3242
return;
3343
}
3444

35-
import('nhsuk-frontend')
45+
importRef.current = import('nhsuk-frontend')
3646
.then(({ Checkboxes }) => setInstance(new Checkboxes(moduleRef.current)))
3747
.catch(setInstanceError);
38-
}, [moduleRef, instance]);
48+
}, [moduleRef, importRef, instance]);
3949

4050
const getBoxId = (id: string, reference: string): string => {
4151
if (reference in _boxIds) {

src/components/form-elements/date-input/DateInput.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
import classNames from 'classnames';
44
import {
5-
createRef,
65
forwardRef,
6+
useImperativeHandle,
7+
useRef,
78
useState,
89
type ChangeEvent,
910
type ComponentPropsWithoutRef,
@@ -43,7 +44,9 @@ export type DateInputType = 'day' | 'month' | 'year';
4344

4445
const DateInputComponent = forwardRef<HTMLDivElement, DateInputProps>(
4546
({ children, onChange, value, defaultValue, formGroupProps, ...rest }, forwardedRef) => {
46-
const [moduleRef] = useState(() => formGroupProps?.ref || createRef<HTMLDivElement>());
47+
const moduleRef = useRef<HTMLDivElement>(null);
48+
49+
useImperativeHandle(formGroupProps?.ref, () => moduleRef.current!, [moduleRef]);
4750

4851
const [internalDate, setInternalDate] = useState<DateInputValue>({
4952
day: value?.day ?? '',

src/components/form-elements/error-summary/ErrorSummary.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import classNames from 'classnames';
44
import { type ErrorSummary as ErrorSummaryModule } from 'nhsuk-frontend';
55
import {
66
Children,
7-
createRef,
87
forwardRef,
98
useEffect,
9+
useImperativeHandle,
10+
useRef,
1011
useState,
1112
type ComponentPropsWithoutRef,
1213
} from 'react';
@@ -19,19 +20,22 @@ export interface ErrorSummaryProps extends ComponentPropsWithoutRef<'div'> {
1920

2021
const ErrorSummaryComponent = forwardRef<HTMLDivElement, ErrorSummaryProps>(
2122
({ children, className, disableAutoFocus, ...rest }, forwardedRef) => {
22-
const [moduleRef] = useState(() => forwardedRef || createRef<HTMLDivElement>());
23+
const moduleRef = useRef<HTMLDivElement>(null);
24+
const importRef = useRef<Promise<ErrorSummaryModule | void>>(null);
2325
const [instanceError, setInstanceError] = useState<Error>();
2426
const [instance, setInstance] = useState<ErrorSummaryModule>();
2527

28+
useImperativeHandle(forwardedRef, () => moduleRef.current!, [moduleRef]);
29+
2630
useEffect(() => {
27-
if (!('current' in moduleRef) || !moduleRef.current || instance) {
31+
if (!moduleRef.current || importRef.current || instance) {
2832
return;
2933
}
3034

31-
import('nhsuk-frontend')
35+
importRef.current = import('nhsuk-frontend')
3236
.then(({ ErrorSummary }) => setInstance(new ErrorSummary(moduleRef.current)))
3337
.catch(setInstanceError);
34-
}, [moduleRef, instance]);
38+
}, [moduleRef, importRef, instance]);
3539

3640
const items = Children.toArray(children);
3741

src/components/form-elements/radios/Radios.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22

33
import classNames from 'classnames';
44
import { type Radios as RadiosModule } from 'nhsuk-frontend';
5-
import { createRef, forwardRef, useEffect, useState, type ComponentPropsWithoutRef } from 'react';
5+
import {
6+
forwardRef,
7+
useEffect,
8+
useImperativeHandle,
9+
useRef,
10+
useState,
11+
type ComponentPropsWithoutRef,
12+
} from 'react';
613
import { RadiosDivider, RadiosItem } from './components/index.js';
714
import { RadiosContext, type IRadiosContext } from './RadiosContext.js';
815
import { FormGroup } from '#components/utils/index.js';
@@ -20,7 +27,8 @@ export interface RadiosProps
2027
const RadiosComponent = forwardRef<HTMLDivElement, RadiosProps>((props, forwardedRef) => {
2128
const { children, idPrefix, ...rest } = props;
2229

23-
const [moduleRef] = useState(() => forwardedRef || createRef<HTMLDivElement>());
30+
const moduleRef = useRef<HTMLDivElement>(null);
31+
const importRef = useRef<Promise<RadiosModule | void>>(null);
2432
const [instanceError, setInstanceError] = useState<Error>();
2533
const [instance, setInstance] = useState<RadiosModule>();
2634
const [selectedRadio, setSelectedRadio] = useState<string>();
@@ -29,15 +37,17 @@ const RadiosComponent = forwardRef<HTMLDivElement, RadiosProps>((props, forwarde
2937
let _radioCount = 0;
3038
let _radioIds: Record<string, string> = {};
3139

40+
useImperativeHandle(forwardedRef, () => moduleRef.current!, [moduleRef]);
41+
3242
useEffect(() => {
33-
if (!('current' in moduleRef) || !moduleRef.current || instance) {
43+
if (!moduleRef.current || importRef.current || instance) {
3444
return;
3545
}
3646

37-
import('nhsuk-frontend')
47+
importRef.current = import('nhsuk-frontend')
3848
.then(({ Radios }) => setInstance(new Radios(moduleRef.current)))
3949
.catch(setInstanceError);
40-
}, [moduleRef, instance]);
50+
}, [moduleRef, importRef, instance]);
4151

4252
const getRadioId = (id: string, reference: string): string => {
4353
if (reference in _radioIds) {

src/components/navigation/header/Header.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import classNames from 'classnames';
44
import { type Header as HeaderModule } from 'nhsuk-frontend';
55
import {
66
Children,
7-
createRef,
87
forwardRef,
98
useEffect,
9+
useImperativeHandle,
1010
useMemo,
11+
useRef,
1112
useState,
1213
type ComponentPropsWithoutRef,
1314
} from 'react';
@@ -34,13 +35,16 @@ const HeaderComponent = forwardRef<HTMLElement, HeaderProps>((props, forwardedRe
3435
const { className, containerClasses, children, logo, service, organisation, white, ...rest } =
3536
props;
3637

37-
const [moduleRef] = useState(() => forwardedRef || createRef<HTMLElement>());
38+
const moduleRef = useRef<HTMLElement>(null);
39+
const importRef = useRef<Promise<HeaderModule | void>>(null);
3840
const [instanceError, setInstanceError] = useState<Error>();
3941
const [instance, setInstance] = useState<HeaderModule>();
4042
const [menuOpen, setMenuOpen] = useState(false);
4143

44+
useImperativeHandle(forwardedRef, () => moduleRef.current!, [moduleRef]);
45+
4246
useEffect(() => {
43-
if (!('current' in moduleRef) || !moduleRef.current || instance) {
47+
if (!moduleRef.current || importRef.current || instance) {
4448
if (!instance) {
4549
return;
4650
}
@@ -58,10 +62,10 @@ const HeaderComponent = forwardRef<HTMLElement, HeaderProps>((props, forwardedRe
5862
return;
5963
}
6064

61-
import('nhsuk-frontend')
65+
importRef.current = import('nhsuk-frontend')
6266
.then(({ Header }) => setInstance(new Header(moduleRef.current)))
6367
.catch(setInstanceError);
64-
}, [moduleRef, instance, menuOpen]);
68+
}, [moduleRef, importRef, instance, menuOpen]);
6569

6670
const contextValue: IHeaderContext = useMemo(() => {
6771
return { menuOpen, setMenuOpen };

0 commit comments

Comments
 (0)