Skip to content

Re-rendering root node breaks dynamic styles #1635

@WalterWeidner

Description

@WalterWeidner

Expected behavior:
The root component of a React app that is using react-jss for styles should be able to re-render and not break the styling of its child components.

Describe the bug:
This bug occurs when the root node of a React app re-renders and then later an instance of a child component unmounts when another instance of the same component mounts.

From my research, it looks like this is caused by the indexOf check in RuleList's remove function. The indexOf uses strict equality checks which fails to find a match after the re-render. The rule is no longer strictly equal due to something with how the provider works. This means that you are splicing with a -1 index, effectively removing the wrong items from the list.

['a', 'b', 'c'].splice(-1, 1)
// ['c']

This could be fixed by refactoring that line in RuleList from:

this.index.splice(this.index.indexOf(rule), 1)

to:

const index = this.index.findIndex(v => v.key === rule.key);
if (index > -1) {
    this.index.splice(index, 1)
}

You could also update the provider so that it doesn't return a different object instance.

Reproduction:
You can see an example of this failure on this codepen. In that example one instance of the component is unmounting while another is mounting. The cleanup function for the first instances's dynamic styles runs after the second instance has created its sheet and it removes the new sheet.

Versions (please complete the following information):

  • jss: 10.9.2
  • Browser [e.g. chrome, safari]: Chrome
  • OS [e.g. Windows, macOS]: macOS

This is possibly related to #917, though that issue has been closed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions