-
Notifications
You must be signed in to change notification settings - Fork 10
/
index.js
96 lines (89 loc) · 3.15 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import React from 'react';
export function useShallowEqual(WrappedComponent) {
class ShallowEqualEnhancer extends WrappedComponent {
shouldComponentUpdate(nextProps, nextState) {
let shouldUpdate = false;
if (!super.shouldComponentUpdate || super.shouldComponentUpdate(nextProps, nextState)) {
shouldUpdate = shallowEqual(this.props, nextProps, this.state, nextState);
}
return shouldUpdate;
}
}
ShallowEqualEnhancer.displayName = `ShallowEqualEnhanced${WrappedComponent.displayName || WrappedComponent.name || 'Component'}`;
return ShallowEqualEnhancer;
}
/**
* Use this function with your "this" in its context.
* @example
* return shouldComponentUpdate.call(this, nextProps, nextState);
* @example
* return shouldComponentUpdate.apply(this, [nextProps, nextState]);
* @example
* return shouldComponentUpdate.bind(this)(nextProps, nextState);
* @param {Object} nextProps
* @param {Object} nextState
*/
export function shouldComponentUpdate(nextProps, nextState) {
return shallowEqual(this.props, nextProps, this.state, nextState);
}
/**
* @param {Object} thisProps
* @param {Object} nextProps
* @param {Object} thisState
* @param {Object} nextState
*/
export function shallowEqual(thisProps, nextProps, thisState, nextState) {
return !shallowEqualState(thisState, nextState) || !shallowEqualWithoutReactElements(thisProps, nextProps);
}
/**
* @param {Object} thisState
* @param {Object} nextState
* @returns {Boolean}
*/
export function shallowEqualState(thisState, nextState) {
return thisState === nextState
}
/**
* Perform a shallow equal to every prop that is not a React Element
* This will return true for unchanged props (where the only changes are the react elements props like 'children')
* @param {Object} thisProps
* @param {Object} nextProps
* @returns {Boolean}
*/
export function shallowEqualWithoutReactElements(thisProps, nextProps) {
let equals = false;
if (thisProps === nextProps) {
equals = true;
} else if (typeof thisProps === 'object' && typeof nextProps === 'object') {
equals = true;
const propNames = new Set(Object.keys(thisProps), Object.keys(nextProps));
for (const propName of propNames) {
if (thisProps[propName] !== nextProps[propName] && !isReactElement(thisProps[propName])) {
// No need to check nextProps[propName] as well, as we know they are not equal
equals = false;
break;
}
}
}
return equals;
}
/**
* If the provided argument is a valid react element or an array that contains at least
* one valid react element in it
* @param {*} suspectedElement
* @returns {Boolean}
*/
function isReactElement(suspectedElement) {
let isElem = false;
if (React.isValidElement(suspectedElement)) {
isElem = true;
} else if (Array.isArray(suspectedElement)) {
for (let i = 0, l = suspectedElement.length; i < l; i++) {
if (React.isValidElement(suspectedElement[i])) {
isElem = true;
break;
}
}
}
return isElem;
}