Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect no-direct-mutation-state Warning #1812

Closed
BrodaNoel opened this issue Jun 7, 2018 · 11 comments
Closed

Incorrect no-direct-mutation-state Warning #1812

BrodaNoel opened this issue Jun 7, 2018 · 11 comments

Comments

@BrodaNoel
Copy link

https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md

This is happening right now:

constructor(props) {
    super(props);

    // No warning here
    this.state.randomId = Math.round(Math.random() * 1000000);

    this.props.tables.forEach((table, i) => {
      if (table.isOpen) {
        // Here we have a warning
        this.state[`table${i}Shown`] = true;
      }
    });
  }
@ljharb
Copy link
Member

ljharb commented Jun 7, 2018

The first one should be throwing at runtime, since this.state is undefined

@BrodaNoel
Copy link
Author

What if I have:

state = {};

constructor(props) {
    super(props);

    // No warning here
    this.state.randomId = Math.round(Math.random() * 1000000);

    this.props.tables.forEach((table, i) => {
      if (table.isOpen) {
        // Here we have a warning
        this.state[`table${i}Shown`] = true;
      }
    });
  }

@ljharb
Copy link
Member

ljharb commented Jun 7, 2018

in that case, I would certainly expect a warning there.

@BrodaNoel
Copy link
Author

Actually there should not be warnings in any of both places

@BrodaNoel
Copy link
Author

The "direct state mutation" is able in any part of the constructor (sync)

@ljharb
Copy link
Member

ljharb commented Jun 7, 2018

The rule only allows assigning this.state in the constructor. It is never OK to mutate it.

@BrodaNoel
Copy link
Author

BrodaNoel commented Jun 7, 2018 via email

@ljharb
Copy link
Member

ljharb commented Jun 7, 2018

Sure - first, the state = {} in the class body is equivalent to putting this.state = {} in the constructor just after the super call. The bug is that the warnings aren’t the same in those two cases.

Second, the rule is designed to prevent any mutation of the state object after it’s created. So, you should see a warning inside the forEach, but also on the randomId line.

In other words, you should build up the entire state object before assigning it to the instance.

@BrodaNoel
Copy link
Author

BrodaNoel commented Jun 7, 2018

Actually, I'm not seen and I should not see a warning in the randomId line.
The state can be manipulated in the constructor as much as we want. It' doesn't affect the React state.

I got your point after checking what you said in #832

I disagree about warning in any place of the constructor. The react-state doesn't know anything about this.state var yet. It's just a var manipulation, not a "React State manipulation". But, anyways... Bug reported.

Thank you a lot for your time.

@ljharb
Copy link
Member

ljharb commented Jun 7, 2018

The point of the rule is to forbid mutating state in the constructor ever. It does, also, have an effect - mutating an object after creation is slower than creating it all at once.

@ljharb
Copy link
Member

ljharb commented Jun 7, 2018

Additionally, mutation of any kind is always a code smell, especially in react. If you want a different object, clone it and assign the new one.

@ljharb ljharb closed this as completed Feb 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

2 participants