diff --git a/CHANGELOG.md b/CHANGELOG.md index 59de70a7..f6ee9797 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Roact Changelog ## Unreleased Changes +* Removed the warning for `setState` on unmounted components ([#323](https://github.com/Roblox/roact/pull/323)). ## [1.4.2](https://github.com/Roblox/roact/releases/tag/v1.4.2) (October 6th, 2021) * Fixed forwardRef doc code referencing React instead of Roact ([#310](https://github.com/Roblox/roact/pull/310)). diff --git a/src/Component.lua b/src/Component.lua index b35754b2..67a0cbf3 100644 --- a/src/Component.lua +++ b/src/Component.lua @@ -100,7 +100,7 @@ function Component:setState(mapState) local lifecyclePhase = internalData.lifecyclePhase --[[ - When preparing to update, rendering, or unmounting, it is not safe + When preparing to update, render, or unmount, it is not safe to call `setState` as it will interfere with in-flight updates. It's also disallowed during unmounting ]] @@ -108,13 +108,14 @@ function Component:setState(mapState) lifecyclePhase == ComponentLifecyclePhase.ShouldUpdate or lifecyclePhase == ComponentLifecyclePhase.WillUpdate or lifecyclePhase == ComponentLifecyclePhase.Render - or lifecyclePhase == ComponentLifecyclePhase.WillUnmount then local messageTemplate = invalidSetStateMessages[internalData.lifecyclePhase] local message = messageTemplate:format(tostring(internalData.componentClass)) - error(message, 2) + elseif lifecyclePhase == ComponentLifecyclePhase.WillUnmount then + -- Should not print error message. See React #22114 + return end local pendingState = internalData.pendingState diff --git a/src/Component.spec/setState.spec.lua b/src/Component.spec/setState.spec.lua index 7e62e507..2cb5d9c2 100644 --- a/src/Component.spec/setState.spec.lua +++ b/src/Component.spec/setState.spec.lua @@ -109,7 +109,7 @@ return function() expect(result:match("TestComponent")).to.be.ok() end) - it("should throw when called in willUnmount", function() + it("should not throw when called in willUnmount", function() local TestComponent = Component:extend("TestComponent") function TestComponent:render() @@ -125,11 +125,9 @@ return function() local element = createElement(TestComponent) local tree = noopReconciler.mountVirtualTree(element) - local success, result = pcall(noopReconciler.unmountVirtualTree, tree) + local success, _ = pcall(noopReconciler.unmountVirtualTree, tree) - expect(success).to.equal(false) - expect(result:match("willUnmount")).to.be.ok() - expect(result:match("TestComponent")).to.be.ok() + expect(success).to.equal(true) end) it("should remove values from state when the value is None", function() diff --git a/src/invalidSetStateMessages.lua b/src/invalidSetStateMessages.lua index 60294bc0..0467bae4 100644 --- a/src/invalidSetStateMessages.lua +++ b/src/invalidSetStateMessages.lua @@ -15,12 +15,6 @@ Consider using the didUpdate method instead, or using getDerivedStateFromProps. Check the definition of willUpdate in the component %q.]] -invalidSetStateMessages[ComponentLifecyclePhase.WillUnmount] = [[ -setState cannot be used in the willUnmount lifecycle method. -A component that is being unmounted cannot be updated! - -Check the definition of willUnmount in the component %q.]] - invalidSetStateMessages[ComponentLifecyclePhase.ShouldUpdate] = [[ setState cannot be used in the shouldUpdate lifecycle method. shouldUpdate must be a pure function that only depends on props and state.