From 846ea48ae3b5d144345ba3b876907eee89862675 Mon Sep 17 00:00:00 2001 From: fiss Date: Wed, 20 Sep 2017 15:37:12 -0700 Subject: [PATCH 1/3] Improving API for unstable shouldUpdate and onUpdate --- src/index.js | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 2a366a6..ce9f2b0 100644 --- a/src/index.js +++ b/src/index.js @@ -24,10 +24,16 @@ function traverseRenderedChildren(internalInstance, callback, argument) { } } +function extractPublicInfoStack(internalInstance) { + return { + publicInstance: internalInstance._instance, + } +} + function setPendingForceUpdate(internalInstance, shouldUpdate) { if ( internalInstance._pendingForceUpdate === false && - shouldUpdate(internalInstance) + (!shouldUpdate || shouldUpdate(extractPublicInfoStack(internalInstance))) ) { internalInstance._pendingForceUpdate = true } @@ -43,7 +49,9 @@ function forceUpdateIfPending(internalInstance, onUpdate) { } else if (updater && typeof updater.enqueueForceUpdate === 'function') { updater.enqueueForceUpdate(publicInstance) } - onUpdate(internalInstance) + if (onUpdate) { + onUpdate(extractPublicInfoStack(internalInstance)) + } } } @@ -57,10 +65,20 @@ function deepForceUpdateStack(instance, shouldUpdate, onUpdate) { traverseRenderedChildren(internalInstance, forceUpdateIfPending, onUpdate) } +function extractPublicInfoFiber(internalInstance) { + const childFileName = internalInstance.child && + internalInstance.child._debugSource && + internalInstance.child._debugSource.fileName; + return { + childFileName, + publicInstance: internalInstance.stateNode, + } +} + export default function deepForceUpdate( instance, - shouldUpdate = () => true, - onUpdate = () => {}, + shouldUpdate, + onUpdate, ) { const root = instance._reactInternalFiber || instance._reactInternalInstance if (typeof root.tag !== 'number') { @@ -70,7 +88,10 @@ export default function deepForceUpdate( let node = root while (true) { - if (node.tag === ReactClassComponent && shouldUpdate(node)) { + if ( + node.tag === ReactClassComponent && + (!shouldUpdate || shouldUpdate(extractPublicInfoFiber(node))) + ) { const publicInstance = node.stateNode const { updater } = publicInstance if (typeof publicInstance.forceUpdate === 'function') { @@ -78,7 +99,9 @@ export default function deepForceUpdate( } else if (updater && typeof updater.enqueueForceUpdate === 'function') { updater.enqueueForceUpdate(publicInstance) } - onUpdate(node) + if (onUpdate) { + onUpdate(extractPublicInfoFiber(node)) + } } if (node.child) { node.child.return = node From 6b26bfb05019670d769a42c0da17f644adffaa36 Mon Sep 17 00:00:00 2001 From: fiss Date: Sat, 23 Sep 2017 17:48:40 -0700 Subject: [PATCH 2/3] Major update --- src/index.js | 107 +++++++++++++++++++++++---------------------- test/index.test.js | 3 +- 2 files changed, 57 insertions(+), 53 deletions(-) diff --git a/src/index.js b/src/index.js index ce9f2b0..f3a7ee3 100644 --- a/src/index.js +++ b/src/index.js @@ -24,22 +24,13 @@ function traverseRenderedChildren(internalInstance, callback, argument) { } } -function extractPublicInfoStack(internalInstance) { - return { - publicInstance: internalInstance._instance, - } -} - -function setPendingForceUpdate(internalInstance, shouldUpdate) { - if ( - internalInstance._pendingForceUpdate === false && - (!shouldUpdate || shouldUpdate(extractPublicInfoStack(internalInstance))) - ) { +function setPendingForceUpdate(internalInstance) { + if (internalInstance._pendingForceUpdate === false) { internalInstance._pendingForceUpdate = true } } -function forceUpdateIfPending(internalInstance, onUpdate) { +function forceUpdateIfPending(internalInstance) { if (internalInstance._pendingForceUpdate === true) { const publicInstance = internalInstance._instance const { updater } = publicInstance @@ -49,74 +40,86 @@ function forceUpdateIfPending(internalInstance, onUpdate) { } else if (updater && typeof updater.enqueueForceUpdate === 'function') { updater.enqueueForceUpdate(publicInstance) } - if (onUpdate) { - onUpdate(extractPublicInfoStack(internalInstance)) - } } } -function deepForceUpdateStack(instance, shouldUpdate, onUpdate) { +function deepForceUpdateStack(instance) { const internalInstance = instance._reactInternalInstance - traverseRenderedChildren( - internalInstance, - setPendingForceUpdate, - shouldUpdate, - ) - traverseRenderedChildren(internalInstance, forceUpdateIfPending, onUpdate) + traverseRenderedChildren(internalInstance, setPendingForceUpdate) + traverseRenderedChildren(internalInstance, forceUpdateIfPending) +} + +function onEnterFiber(node, toUpdate, shouldUpdate) { + if (!toUpdate) { + return undefined + } + if (node.tag === ReactClassComponent) { + toUpdate.push(shouldUpdate( + node.tag, + node.stateNode, + node._debugSource && node._debugSource.fileName, + )) + } else if (!toUpdate[toUpdate.length - 1]) { + toUpdate[toUpdate.length - 1] = shouldUpdate( + node.tag, + null, // publicInstance + node._debugSource && node._debugSource.fileName, + ) + } + return undefined } -function extractPublicInfoFiber(internalInstance) { - const childFileName = internalInstance.child && - internalInstance.child._debugSource && - internalInstance.child._debugSource.fileName; - return { - childFileName, - publicInstance: internalInstance.stateNode, +function onLeaveFiber(node, toUpdate, onUpdate) { + if (node.tag !== ReactClassComponent || (toUpdate && !toUpdate.pop())) { + return undefined + } + const publicInstance = node.stateNode + const { updater } = publicInstance + if (typeof publicInstance.forceUpdate === 'function') { + publicInstance.forceUpdate() + } else if ( + updater && typeof updater.enqueueForceUpdate === 'function' + ) { + updater.enqueueForceUpdate(publicInstance) } + if (onUpdate) { + onUpdate(publicInstance) + } + return undefined } export default function deepForceUpdate( instance, - shouldUpdate, - onUpdate, + shouldUpdateClosestClassInstance, + onUpdateClassInstance, ) { const root = instance._reactInternalFiber || instance._reactInternalInstance if (typeof root.tag !== 'number') { + if (shouldUpdateClosestClassInstance || onUpdateClassInstance) { + throw new Error('shouldUpdateClosestClassInstance and ' + + 'onUpdateClassInstance are only supported in React Fiber') + } // Traverse stack-based React tree. - return deepForceUpdateStack(instance, shouldUpdate, onUpdate) + return deepForceUpdateStack(instance) } let node = root + const toUpdate = shouldUpdateClosestClassInstance ? [] : null while (true) { - if ( - node.tag === ReactClassComponent && - (!shouldUpdate || shouldUpdate(extractPublicInfoFiber(node))) - ) { - const publicInstance = node.stateNode - const { updater } = publicInstance - if (typeof publicInstance.forceUpdate === 'function') { - publicInstance.forceUpdate() - } else if (updater && typeof updater.enqueueForceUpdate === 'function') { - updater.enqueueForceUpdate(publicInstance) - } - if (onUpdate) { - onUpdate(extractPublicInfoFiber(node)) - } - } + onEnterFiber(node, toUpdate, shouldUpdateClosestClassInstance) if (node.child) { node.child.return = node node = node.child continue } - if (node === root) { - return undefined - } - while (!node.sibling) { - if (!node.return || node.return === root) { + while (!node.sibling || node === root) { + onLeaveFiber(node, toUpdate, onUpdateClassInstance) + if (!node.return || node === root) { return undefined } node = node.return } + onLeaveFiber(node, toUpdate, onUpdateClassInstance) node.sibling.return = node.return node = node.sibling } diff --git a/test/index.test.js b/test/index.test.js index 7092617..d7d9258 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -198,6 +198,7 @@ describe('force update', () => { }) it('respects shouldUpdate and onUpdate arguments', () => { - expectNoUpdate(PureWrapperStrict, PureWrapperStrict) + // Re-enable this once we support process.env.REACT_JEST_USE_FIBER = true + expect(() => expectNoUpdate(PureWrapperStrict, PureWrapperStrict)).toThrow() }) }) From 82d2368445f812d79b77f43b71d461466d2b05e1 Mon Sep 17 00:00:00 2001 From: fiss Date: Mon, 2 Oct 2017 16:46:23 -0700 Subject: [PATCH 3/3] Updating to React 16 --- package.json | 4 ++-- test/index.test.js | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 19ee576..8e08368 100644 --- a/package.json +++ b/package.json @@ -43,8 +43,8 @@ "eslint-plugin-react": "^7.1.0", "jest": "^21.1.0", "prettier": "^1.7.0", - "react": "^15.6.1", - "react-dom": "^15.6.1", + "react": "^16.0.0", + "react-dom": "^16.0.0", "rimraf": "^2.6.2" } } diff --git a/test/index.test.js b/test/index.test.js index d7d9258..7092617 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -198,7 +198,6 @@ describe('force update', () => { }) it('respects shouldUpdate and onUpdate arguments', () => { - // Re-enable this once we support process.env.REACT_JEST_USE_FIBER = true - expect(() => expectNoUpdate(PureWrapperStrict, PureWrapperStrict)).toThrow() + expectNoUpdate(PureWrapperStrict, PureWrapperStrict) }) })