inferno: patchComponent: Cannot read property '_unmounted' of null

Observed Behaviour

Inferno is throwing and uncaught exception Cannot read property '_unmounted' of null. It is happening inside patchComponent when lastVNode.children is null. It is throwing because instance._unmounted is null to be more specific.

https://github.com/infernojs/inferno/blob/8a605aba148136678f1e7689064b1deb535ac1a5/packages/inferno/src/DOM/patching.ts#L289

Expected Current Behaviour

Inferno should not throw an uncaught exception, but should handle null as children appropriately.

Inferno Metadata

Using inferno/inferno-compat v1.3.0-rc.8

macOS / Chrome

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 2
  • Comments: 35 (27 by maintainers)

Commits related to this issue

Most upvoted comments

Good news this will be fixed in 1.5

  • Using setStateSync will still fail due to its synchronous nature.
  • setState will start going async now correctly and this issue wont happen

Ok, I have found the root cause of the issue. I’ll do my best to explain, but @Omlet is correct it is directly related to dispatching actions from within componentWillReceiveProps in a child component.

Let’s say you have component A, a container component wrapped with the connect higher order component from react-redux and component B, a child of Component A that will react to changes in props or state by dispatching an action from within componentWillReceiveProps.

In some other child component of component A, a button is clicked that dispatches an action and causes component A to be patched. During the patch method it synchronously steps through each component in the tree and patches the component. Once it reaches component B, it calls the _updateComponent method and that calls this.componentWillReceiveProps since it is defined.

Inside componentWillReceiveProps a new action is dispatched based on the props for component B changing, which is a synchronous function that results in the listener in react-redux’s higher order component being fired. This in turn leads to a call to this.setState from within the Connect higher order component, which has this._syncSetState set to true so it is done synchronously.

The Connect higher order component is wrapping the parent component (component A) and the sync set state triggers that component to be patched synchronously immediately. When this patch happens, the initial patch on component A did not finish and the instances for all of it’s children have not been set because instance._lastInput = nextInput; inside of the initial patch set the _lastInput property to nextInput already but the patch for nextInput did not complete. Any component that would have been patched AFTER component B has a null children property due to patch never reaching it.

This is hard to explain, but I hope you understand what I am saying. If you have any questions please let me know and I can try to get a repo up that demonstrates the issue. In order to unit test this, you would have to either use the react-redux connect higher order component or create a HoC that does something similar to create the patch loop that causes the children instances to be null.