UNPKG

2.29 kBJavaScriptView Raw
1function shouldDeleteClassicInstanceMethod(component, name) {
2 if (component.__reactAutoBindMap.hasOwnProperty(name)) {
3 // It's a known autobound function, keep it
4 return false;
5 }
6
7 if (component[name].__reactBoundArguments !== null) {
8 // It's a function bound to specific args, keep it
9 return false;
10 }
11
12 // It's a cached bound method for a function
13 // that was deleted by user, so we delete it from component.
14 return true;
15}
16
17function shouldDeleteModernInstanceMethod(component, name) {
18 const { prototype } = component.constructor;
19 const prototypeDescriptor = Object.getOwnPropertyDescriptor(prototype, name);
20
21 if (!prototypeDescriptor || !prototypeDescriptor.get) {
22 // This is definitely not an autobinding getter
23 return false;
24 }
25
26 if (prototypeDescriptor.get().length !== component[name].length) {
27 // The length doesn't match, bail out
28 return false;
29 }
30
31 // This seems like a method bound using an autobinding getter on the prototype
32 // Hopefully we won't run into too many false positives.
33 return true;
34}
35
36function shouldDeleteInstanceMethod(component, name) {
37 const descriptor = Object.getOwnPropertyDescriptor(component, name);
38 if (typeof descriptor.value !== 'function') {
39 // Not a function, or something fancy: bail out
40 return;
41 }
42
43 if (component.__reactAutoBindMap) {
44 // Classic
45 return shouldDeleteClassicInstanceMethod(component, name);
46 } else {
47 // Modern
48 return shouldDeleteModernInstanceMethod(component, name);
49 }
50}
51
52/**
53 * Deletes autobound methods from the instance.
54 *
55 * For classic React classes, we only delete the methods that no longer exist in map.
56 * This means the user actually deleted them in code.
57 *
58 * For modern classes, we delete methods that exist on prototype with the same length,
59 * and which have getters on prototype, but are normal values on the instance.
60 * This is usually an indication that an autobinding decorator is being used,
61 * and the getter will re-generate the memoized handler on next access.
62 */
63export default function deleteUnknownAutoBindMethods(component) {
64 const names = Object.getOwnPropertyNames(component);
65
66 names.forEach(name => {
67 if (shouldDeleteInstanceMethod(component, name)) {
68 delete component[name];
69 }
70 });
71}