Skip to content
This repository was archived by the owner on Dec 30, 2022. It is now read-only.

Commit 9174806

Browse files
authored
feat(core): support react 18 strict mode (#3653)
1 parent ff72a02 commit 9174806

File tree

4 files changed

+56
-27
lines changed

4 files changed

+56
-27
lines changed

packages/react-instantsearch-core/src/core/__tests__/createConnector.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import createConnector, {
55
createConnectorWithoutContext,
66
} from '../createConnector';
77
import { InstantSearchProvider } from '../context';
8+
import { wait } from '../../../../../test/utils';
89

910
Enzyme.configure({ adapter: new Adapter() });
1011

@@ -415,7 +416,7 @@ describe('createConnector', () => {
415416
expect(subscribe).toHaveBeenCalledTimes(1);
416417
});
417418

418-
it('unsubscribes from the store on unmount', () => {
419+
it('unsubscribes from the store on unmount', async () => {
419420
const Connected = createConnectorWithoutContext({
420421
displayName: 'Connector',
421422
getProvidedProps: () => {},
@@ -435,6 +436,8 @@ describe('createConnector', () => {
435436

436437
wrapper.unmount();
437438

439+
await wait(0);
440+
438441
expect(unsubscribe).toHaveBeenCalledTimes(1);
439442
});
440443

@@ -787,7 +790,7 @@ describe('createConnector', () => {
787790
expect(onSearchStateChange).not.toHaveBeenCalled();
788791
});
789792

790-
it('unregisters itself on unmount', () => {
793+
it('unregisters itself on unmount', async () => {
791794
const Connected = createConnectorWithoutContext({
792795
displayName: 'Connector',
793796
getProvidedProps: () => {},
@@ -808,10 +811,12 @@ describe('createConnector', () => {
808811

809812
wrapper.unmount();
810813

814+
await wait(0);
815+
811816
expect(unregisterWidget).toHaveBeenCalledTimes(1);
812817
});
813818

814-
it('calls onSearchStateChange with cleanUp on unmount', () => {
819+
it('calls onSearchStateChange with cleanUp on unmount', async () => {
815820
const cleanUp = jest.fn(function (props, searchState) {
816821
return {
817822
instanceProps: this.props,
@@ -858,6 +863,8 @@ describe('createConnector', () => {
858863

859864
wrapper.unmount();
860865

866+
await wait(0);
867+
861868
expect(cleanUp).toHaveBeenCalledTimes(1);
862869
expect(onSearchStateChange).toHaveBeenCalledTimes(1);
863870
expect(onSearchStateChange).toHaveBeenCalledWith({
@@ -875,7 +882,7 @@ describe('createConnector', () => {
875882
});
876883
});
877884

878-
it('calls onSearchStateChange with cleanUp without empty keys on unmount', () => {
885+
it('calls onSearchStateChange with cleanUp without empty keys on unmount', async () => {
879886
const cleanUp = jest.fn((_, searchState) => searchState);
880887

881888
const Connected = createConnectorWithoutContext({
@@ -910,6 +917,8 @@ describe('createConnector', () => {
910917

911918
wrapper.unmount();
912919

920+
await wait(0);
921+
913922
expect(onSearchStateChange).toHaveBeenCalledWith({
914923
query: 'hello',
915924
});

packages/react-instantsearch-core/src/core/createConnector.tsx

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export function createConnectorWithoutContext(
102102
unsubscribe?: () => void;
103103
unregisterWidget?: () => void;
104104

105+
cleanupTimerRef: ReturnType<typeof setTimeout> | null = null;
105106
isUnmounting = false;
106107

107108
state: ConnectorState = {
@@ -126,6 +127,11 @@ export function createConnectorWithoutContext(
126127
}
127128

128129
componentDidMount() {
130+
if (this.cleanupTimerRef) {
131+
clearTimeout(this.cleanupTimerRef);
132+
this.cleanupTimerRef = null;
133+
}
134+
129135
this.unsubscribe = this.props.contextValue.store.subscribe(() => {
130136
if (!this.isUnmounting) {
131137
this.setState({
@@ -193,32 +199,34 @@ export function createConnectorWithoutContext(
193199
}
194200

195201
componentWillUnmount() {
196-
this.isUnmounting = true;
202+
this.cleanupTimerRef = setTimeout(() => {
203+
this.isUnmounting = true;
197204

198-
if (this.unsubscribe) {
199-
this.unsubscribe();
200-
}
205+
if (this.unsubscribe) {
206+
this.unsubscribe();
207+
}
201208

202-
if (this.unregisterWidget) {
203-
this.unregisterWidget();
209+
if (this.unregisterWidget) {
210+
this.unregisterWidget();
204211

205-
if (typeof connectorDesc.cleanUp === 'function') {
206-
const nextState = connectorDesc.cleanUp.call(
207-
this,
208-
this.props,
209-
this.props.contextValue.store.getState().widgets
210-
);
212+
if (typeof connectorDesc.cleanUp === 'function') {
213+
const nextState = connectorDesc.cleanUp.call(
214+
this,
215+
this.props,
216+
this.props.contextValue.store.getState().widgets
217+
);
211218

212-
this.props.contextValue.store.setState({
213-
...this.props.contextValue.store.getState(),
214-
widgets: nextState,
215-
});
219+
this.props.contextValue.store.setState({
220+
...this.props.contextValue.store.getState(),
221+
widgets: nextState,
222+
});
216223

217-
this.props.contextValue.onSearchStateChange(
218-
removeEmptyKey(nextState)
219-
);
224+
this.props.contextValue.onSearchStateChange(
225+
removeEmptyKey(nextState)
226+
);
227+
}
220228
}
221-
}
229+
});
222230
}
223231

224232
getProvidedProps(props) {

packages/react-instantsearch-core/src/widgets/InstantSearch.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ class InstantSearch extends Component<Props, State> {
175175
};
176176
}
177177

178+
cleanupTimerRef: ReturnType<typeof setTimeout> | null = null;
178179
isUnmounting: boolean = false;
179180

180181
constructor(props: Props) {
@@ -235,6 +236,11 @@ class InstantSearch extends Component<Props, State> {
235236
}
236237

237238
componentDidMount() {
239+
if (this.cleanupTimerRef) {
240+
clearTimeout(this.cleanupTimerRef);
241+
this.cleanupTimerRef = null;
242+
}
243+
238244
if (isMetadataEnabled()) {
239245
injectMetadata(
240246
this.state.instantSearchManager.widgetsManager.getWidgets(),
@@ -244,8 +250,10 @@ class InstantSearch extends Component<Props, State> {
244250
}
245251

246252
componentWillUnmount() {
247-
this.isUnmounting = true;
248-
this.state.instantSearchManager.skipSearch();
253+
this.cleanupTimerRef = setTimeout(() => {
254+
this.isUnmounting = true;
255+
this.state.instantSearchManager.skipSearch();
256+
});
249257
}
250258

251259
createHrefForState(searchState: SearchState) {

packages/react-instantsearch-core/src/widgets/__tests__/InstantSearch.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
44
import createInstantSearchManager from '../../core/createInstantSearchManager';
55
import InstantSearch from '../InstantSearch';
66
import { InstantSearchConsumer } from '../../core/context';
7+
import { wait } from '../../../../../test/utils';
78

89
Enzyme.configure({ adapter: new Adapter() });
910

@@ -330,7 +331,7 @@ describe('InstantSearch', () => {
330331
expect(childContext.widgetsManager).toBe(ism.widgetsManager);
331332
});
332333

333-
it('onSearchStateChange should not be called and search should be skipped if the widget is unmounted', () => {
334+
it('onSearchStateChange should not be called and search should be skipped if the widget is unmounted', async () => {
334335
const ism = createFakeInstantSearchManager();
335336
let childContext;
336337
createInstantSearchManager.mockImplementation(() => ism);
@@ -350,6 +351,9 @@ describe('InstantSearch', () => {
350351
);
351352

352353
wrapper.unmount();
354+
355+
await wait(0);
356+
353357
childContext.onSearchStateChange({});
354358

355359
expect(onSearchStateChangeMock).toHaveBeenCalledTimes(0);

0 commit comments

Comments
 (0)