Skip to content
This repository was archived by the owner on Feb 14, 2023. It is now read-only.

Commit 78cd61e

Browse files
umbertoghiosiapdev
authored andcommitted
✨using shouldComponentUpdate from React 16.3.x (#147)
* ✨using shouldComponentUpdate from React 16.3.x * 🐞 Fix shouldComponentUpdatePrototype returns * Improve comments * 🐞 Use appropriate lifecycle method for PureComponents * 🐞 Fix ReactNCShouldComponentUpdate Typo * Cleanup shouldComponentUpdate for Decorator Co-authored-by: Umberto Ghio <ughio@siapcn.it>
1 parent 003a368 commit 78cd61e

File tree

5 files changed

+125
-32
lines changed

5 files changed

+125
-32
lines changed

src/decorator.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ const isComponentDidMount = false;
2121
const isComponentDidUpdate = false;
2222
const isSetGlobalCallback = false;
2323

24+
const [ rVerMaj, rVerMin ] = version.split('.').map((v): number => parseInt(v));
25+
const isUsingOldReact = rVerMaj < 16 || (rVerMaj === 16 && rVerMin < 3);
26+
2427
// Get the name of a Component.
2528
const componentName = <
2629
P extends {} = {},
@@ -44,7 +47,7 @@ export default function ReactN<
4447
class DecoratedReactNComponent extends DecoratedComponent {
4548

4649
public static displayName: string =
47-
`${componentName(DecoratedComponent)}-ReactN`;
50+
`${componentName(DecoratedComponent)}-ReactN`;
4851

4952
public constructor(props: Readonly<P>, context?: any) {
5053
super(props, context);
@@ -58,23 +61,21 @@ export default function ReactN<
5861
}
5962
}
6063

61-
public UNSAFE_componentWillUpdate(...args: [ P, S, any ]): void {
62-
const [ rVerMaj, rVerMin ] = version.split('.').map((v): number => parseInt(v));
63-
if (rVerMaj > 16 || (rVerMaj === 16 && rVerMin >= 3)) {
64+
public componentWillUpdate(...args: [ P, S, any ]): void {
65+
if (isUsingOldReact) {
6466
ReactNComponentWillUpdate(this);
6567
}
66-
if (super.UNSAFE_componentWillUpdate) {
67-
super.UNSAFE_componentWillUpdate(...args);
68+
if (super.componentWillUpdate) {
69+
super.componentWillUpdate(...args);
6870
}
6971
}
7072

71-
public componentWillUpdate(...args: [ P, S, any ]): void {
72-
const [ rVerMaj, rVerMin ] = version.split('.').map((v): number => parseInt(v));
73-
if (rVerMaj < 16 || (rVerMaj === 16 && rVerMin < 3)) {
73+
public UNSAFE_componentWillUpdate(...args: [ P, S, any ]): void {
74+
if (!isUsingOldReact) {
7475
ReactNComponentWillUpdate(this);
7576
}
76-
if (super.componentWillUpdate) {
77-
super.componentWillUpdate(...args);
77+
if (super.UNSAFE_componentWillUpdate) {
78+
super.UNSAFE_componentWillUpdate(...args);
7879
}
7980
}
8081

src/methods.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function ReactNComponentWillUnmount<G extends {} = State>(
5454

5555

5656

57-
// this.componentWillUnmount
57+
// this.componentWillUpdate
5858
export function ReactNComponentWillUpdate<G extends {} = State>(
5959
that: ReactNComponent<any, any, G> | ReactNPureComponent<any, any, G>,
6060
): void {
@@ -63,6 +63,14 @@ export function ReactNComponentWillUpdate<G extends {} = State>(
6363
getGlobalStateManager<G>().removePropertyListener(that._globalCallback);
6464
}
6565

66+
// this.shouldComponentUpdate
67+
export function ReactNShouldComponentUpdate<G extends {} = State>(
68+
that: ReactNComponent<any, any, G> | ReactNPureComponent<any, any, G>,
69+
): void {
70+
71+
// No longer re-render this component on global state change.
72+
getGlobalStateManager<G>().removePropertyListener(that._globalCallback);
73+
}
6674

6775

6876
// this.dispatch

src/utils/bind-lifecycle-methods.ts

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React = require('react');
44
import {
55
ReactNComponentWillUnmount,
66
ReactNComponentWillUpdate,
7+
ReactNShouldComponentUpdate,
78
} from '../methods';
89
import {
910
// componentWillUnmountInstance,
@@ -13,6 +14,10 @@ import {
1314
// componentWillUpdateInstance,
1415
componentWillUpdatePrototype,
1516
} from './component-will-update';
17+
import {
18+
// shouldComponentUpdateInstance,
19+
shouldComponentUpdatePrototype,
20+
} from './should-component-update';
1621

1722

1823

@@ -38,21 +43,45 @@ export default function bindLifecycleMethods<
3843
};
3944
}
4045

46+
const [ rVerMaj, rVerMin ] = React.version.split('.').map((v): number => parseInt(v));
47+
const isPureComponent = React.PureComponent && (that instanceof React.PureComponent);
48+
const isUsingOldReact = rVerMaj < 16 || (rVerMaj === 16 && rVerMin < 3);
49+
4150
if (
4251
// !componentWillUpdateInstance(that) &&
43-
!componentWillUpdatePrototype(that)
52+
isUsingOldReact && !componentWillUpdatePrototype(that)
4453
) {
45-
const [ rVerMaj, rVerMin ] = React.version.split('.').map((v): number => parseInt(v));
46-
if (rVerMaj > 16 || (rVerMaj === 16 && rVerMin >= 3)) {
47-
that.UNSAFE_componentWillUpdate = (): void => {
48-
ReactNComponentWillUpdate(that);
49-
};
50-
} else {
51-
that.componentWillUpdate = (): void => {
52-
ReactNComponentWillUpdate(that);
53-
};
54-
}
54+
// This will fire if using an Old React Version
5555
// Warning: If componentWillUpdate is defined in the constructor (or as an
5656
// arrow function), this will be overridden.
57+
that.componentWillUpdate = (): void => {
58+
ReactNComponentWillUpdate(that);
59+
};
60+
}
61+
62+
if (
63+
// !componentWillUpdateInstance(that) &&
64+
!isUsingOldReact && isPureComponent && !componentWillUpdatePrototype(that)
65+
) {
66+
// This will fire if using New React Versions and component is Pure.
67+
// TODO: Firgure out a way to move out UNSAFE methods as can't use shouldComponentUpdate on Pure Components.
68+
// Warning: If UNSAFE_componentWillUpdate is defined in the constructor (or as an
69+
// arrow function), this will be overridden.
70+
that.UNSAFE_componentWillUpdate = (): void => {
71+
ReactNComponentWillUpdate(that);
72+
};
73+
}
74+
75+
if (
76+
// !shouldComponentUpdateInstance(that) &&
77+
!isUsingOldReact && !isPureComponent && !shouldComponentUpdatePrototype(that)
78+
) {
79+
// This will fire if using New React Versions and regular components
80+
// Warning: If shouldComponentUpdate is defined in the constructor (or as an
81+
// arrow function), this will be overridden.
82+
that.shouldComponentUpdate = (): boolean => {
83+
ReactNShouldComponentUpdate(that);
84+
return true; // If shouldComponentUpdate is not defined it defaults to true
85+
};
5786
}
5887
};

src/utils/component-will-update.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Reducers, State } from '../../default';
22
import { ReactNComponent, ReactNPureComponent } from '../../types/component';
33
import { ReactNComponentWillUpdate } from '../methods';
4-
4+
import React = require('react');
55

66

77
/*
@@ -46,14 +46,9 @@ export const componentWillUpdatePrototype = <
4646
): boolean => {
4747
const proto: ReactNComponent | ReactNPureComponent =
4848
Object.getPrototypeOf(that);
49-
if (Object.prototype.hasOwnProperty.call(proto, 'UNSAFE_componentWillUpdate')) {
50-
that.UNSAFE_componentWillUpdate = (...args: [ P, S, any ]): void => {
51-
ReactNComponentWillUpdate(that);
52-
proto.UNSAFE_componentWillUpdate.bind(that)(...args);
53-
};
54-
return true;
55-
}
56-
if (Object.prototype.hasOwnProperty.call(proto, 'componentWillUpdate')) {
49+
const [ rVerMaj, rVerMin ] = React.version.split('.').map((v): number => parseInt(v));
50+
if (Object.prototype.hasOwnProperty.call(proto, 'componentWillUpdate')
51+
&& ((rVerMaj < 16 || (rVerMaj === 16 && rVerMin < 3)))) { // Using old react version
5752
that.componentWillUpdate = (...args: [ P, S, any ]): void => {
5853
ReactNComponentWillUpdate(that);
5954
proto.componentWillUpdate.bind(that)(...args);
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Reducers, State } from '../../default';
2+
import { ReactNComponent, ReactNPureComponent } from '../../types/component';
3+
import { ReactNShouldComponentUpdate } from '../methods';
4+
import React = require('react');
5+
6+
7+
/*
8+
type ShouldComponentUpdate<P extends {} = {}, S extends {} = {}> =
9+
(nextProps: P, nextState: S, context: any) => void;
10+
*/
11+
12+
13+
14+
// this.shouldComponentUpdate on instance
15+
/*
16+
export const shouldComponentUpdateInstance = <
17+
P extends {} = {},
18+
S extends {} = {},
19+
G extends {} = State,
20+
R extends {} = Reducers,
21+
SS = any,
22+
>(
23+
that: ReactNComponent<P, S, G, R, SS> | ReactNPureComponent<P, S, G, R, SS>,
24+
): boolean => {
25+
if (Object.prototype.hasOwnProperty.call(that, 'shouldComponentUpdate')) {
26+
const instanceCwu: ShouldComponentUpdate<P, S> = that.shouldComponentUpdate;
27+
that.shouldComponentUpdate = (...args: [ P, S, any ]): void => {
28+
ReactNShouldComponentUpdate(that);
29+
instanceCwu(...args);
30+
};
31+
return true;
32+
}
33+
return false;
34+
};
35+
*/
36+
37+
// this.shouldComponentUpdate on prototype
38+
export const shouldComponentUpdatePrototype = <
39+
P extends {} = {},
40+
S extends {} = {},
41+
G extends {} = State,
42+
R extends {} = Reducers,
43+
SS = any,
44+
>(
45+
that: ReactNComponent<P, S, G, R, SS> | ReactNPureComponent<P, S, G, R, SS>,
46+
): boolean => {
47+
48+
const proto: ReactNComponent | ReactNPureComponent =
49+
Object.getPrototypeOf(that);
50+
const [ rVerMaj, rVerMin ] = React.version.split('.').map((v): number => parseInt(v));
51+
if (Object.prototype.hasOwnProperty.call(proto, 'shouldComponentUpdate')
52+
&& ((rVerMaj > 16 || (rVerMaj === 16 && rVerMin >= 3)))) {
53+
that.shouldComponentUpdate = (...args: [ P, S, any ]): boolean => {
54+
ReactNShouldComponentUpdate(that);
55+
return proto.shouldComponentUpdate.bind(that)(...args); // Returns outcome of shouldComponentUpdate method
56+
};
57+
return true;
58+
}
59+
return false;
60+
};

0 commit comments

Comments
 (0)