Skip to content

Commit b24ea78

Browse files
committed
memoized dispatch
1 parent a94c6f9 commit b24ea78

File tree

3 files changed

+44
-20
lines changed

3 files changed

+44
-20
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "use-force-update",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"author": "Charles Stover <use-force-update@charlesstover.com>",
55
"bugs": {
66
"email" : "use-force-update@charlesstover.com",

src/use-force-update.ts

+14-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1-
import { useReducer } from 'react';
1+
import { useMemo, useReducer } from 'react';
22

33
type VoidFunction = () => void;
4-
type VoidFunctionCreator = () => VoidFunction;
5-
type ToggleReducer = (state: boolean, action: void) => boolean;
64

7-
const reducer: ToggleReducer = state => !state;
5+
const reducer = (state: boolean, _action: null): boolean => !state;
86

9-
const useForceUpdate: VoidFunctionCreator = () => {
10-
const [, dispatch] = useReducer(reducer, true);
11-
return dispatch as VoidFunction;
7+
const useForceUpdate = (): VoidFunction => {
8+
const [ , dispatch] = useReducer<boolean, null>(reducer, true);
9+
10+
// Turn dispatch(required_parameter) into dispatch().
11+
const memoizedDispatch = useMemo(
12+
(): VoidFunction =>
13+
(): void => {
14+
dispatch(null);
15+
},
16+
[ dispatch ]
17+
);
18+
return memoizedDispatch;
1219
};
1320

1421
export default useForceUpdate;

tests/use-force-update.spec.tsx

+29-12
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,57 @@
11
import { expect } from 'chai';
22
import * as React from 'react';
33
import * as TestRenderer from 'react-test-renderer';
4-
import useForceUpdate from '../src/use-force-update';
4+
import useForceUpdate from '../use-force-update';
5+
6+
type VoidFunction = () => void;
57

68
describe('useForceUpdate', () => {
7-
let forceUpdate: () => void;
9+
const forceUpdates: VoidFunction[] = [];
810
let renders: number;
9-
let TestComponent: React.FunctionComponent<{}>;
11+
let TestComponent: React.FunctionComponent<{}> = () => null;
1012

1113
beforeEach(() => {
1214

15+
// Reset array of forceUpdate functions.
16+
forceUpdates.splice(0, forceUpdates.length);
17+
1318
// Reset render count.
1419
renders = 0;
1520

1621
// Create the component.
1722
// This creates a new forceUpdate hook for each test.
1823
TestComponent = () => {
19-
forceUpdate = useForceUpdate();
24+
forceUpdates.push(useForceUpdate());
2025
renders++;
2126
return null;
2227
};
2328

2429
});
2530

26-
it('should update a component', () => {
31+
it('should accept no parameters', () => {
32+
TestRenderer.create(<TestComponent />);
33+
expect(forceUpdates[0].length).to.equal(0);
34+
});
35+
36+
it('should maintain the same reference', () => {
37+
TestRenderer.create(<TestComponent />);
38+
forceUpdates[0]();
39+
expect(forceUpdates[0]).to.equal(forceUpdates[1]);
40+
});
41+
42+
it('should return undefined', () => {
43+
TestRenderer.create(<TestComponent />);
44+
expect(forceUpdates[0]()).to.be.undefined;
45+
});
46+
47+
it('should update the component', () => {
2748
expect(renders).to.equal(0);
2849
TestRenderer.create(<TestComponent />);
2950
expect(renders).to.equal(1);
30-
forceUpdate();
51+
forceUpdates[0]();
3152
expect(renders).to.equal(2);
32-
});
33-
34-
it('update function should return undefined', () => {
35-
expect(forceUpdate()).to.be.undefined;
36-
// @ts-ignore test with parameters :shrug:
37-
expect(forceUpdate('anything')).to.be.undefined;
53+
forceUpdates[1]();
54+
expect(renders).to.equal(3);
3855
});
3956

4057
});

0 commit comments

Comments
 (0)