9

I'm learning React and I have Eslint installed in my project. It started giving me errors like

Use callback in setState when referencing the previous state. (react/no-access-state-in-setstate)
Must use destructuring state assignment (react/destructuring-assignment)

I tried to look this up but couldn't understand properly.

Can someone point me in the right direction with this?

Here is my code that throws the errors:

class LoginForm extends React.Component {
  state = {
    data: {
      email: "",
      password: "",
    },
    loading: false,
    errors: {},
  };

  onChange = e =>
    this.setState({
      data: { ...this.state.data, [e.target.name]: e.target.value },
    });

  onSubmit = () => {
    const errors = this.validate(this.state.data);
    this.setState({ errors });

    if (Object.keys(errors).length === 0) {
      this.setState({ loading: true });
      this.props
        .submit(this.state.data)
        .catch(err =>
          this.setState({
            errors: err.response.data.errors,
            loading: false,
          }),
        );
    }
  };
}

As I understand I would need to destructure this.state and this.props but how?

EDIT: After following the suggestions below, I ended up with this. All I need to fix right now is the props. Its asking me to use a destructuring props assignment.

onChange = ({ target: { name, value } }) =>
    this.setState(prevState => ({
        data: { ...prevState.data, [name]: value }
    }));

onSubmit = () => {
    const { data } = this.state;
    const errors = this.validate(data);
    this.setState({ errors });

    if (Object.keys(errors).length === 0) {
        this.setState({ loading: true });
        this.props
            .submit(data)
            .catch(err =>
                this.setState({ errors: err.response.data.errors, loading: false })
            );
    }
};

Thanks in advance and sorry for the newbie question.

dragi
  • 1,462
  • 5
  • 16
  • 28
  • 6
    `setState` is async. so if you call `setState` and use the previous state you might use the wrong one! so use callback to get the previous and use it in a safe way. [This](https://medium.com/@voonminghann/when-to-use-callback-function-of-setstate-in-react-37fff67e5a6c) might be helpful – Maor Refaeli Aug 28 '18 at 10:48
  • Thanks! I'll check it out. – dragi Aug 28 '18 at 10:49
  • Hey What does it mean by ```...state``` in redux. How to destructure in redux – Prashanth Yarram Dec 13 '21 at 19:12
  • I used this solution https://stackoverflow.com/a/52565081/1770571 and it works properly with me – Salma Gomaa Mar 14 '22 at 08:30

3 Answers3

23

What eslint is telling you with the react/destructuring-assignments error is that assignments like:

const data = this.state.data;

can be rewritten into:

const { data } = this.state;

This also works for function arguments, so:

onChange = e => { ... }

can be written as

onChange = ({target: {value, name}}) => { ... }

The next error for react/no-access-state-in-setstate tells you that you are writing:

this.setState({
    data: { ...this.state.data, [e.target.name]: e.target.value }
});

when you should be writing:

this.setState(prevState => ({
    data: { ...prevState.data, [e.target.name]: e.target.value }
}));

or, if you combine it with the react/destructuring-assignments rule:

onChange = ({target: {name, value}}) =>
    this.setState(prevState => ({
        data: { ...prevState.data, [name]: value }
    }));

You can read more about those two rules here:

react/destructuring-assignment

react/no-access-state-in-setstate

Joliver
  • 520
  • 3
  • 10
  • 1
    2nd last way will throw an error, check [this answer](https://stackoverflow.com/questions/45483492/accessing-event-target-inside-callback-in-react/45483658#45483658) for more details. – Mayank Shukla Aug 28 '18 at 11:11
  • 1
    This has worked for me, I edited my original post with the new question. I'm fine with the states now. All I need to edit the props but its a bit more complicated than the example above. – dragi Aug 28 '18 at 16:58
  • 1
    In this case you can just write: `const {submit} = this.props;` and then call `submit(data).catch(...)`. – Joliver Aug 28 '18 at 17:03
  • Amazing. It kind of makes sense now. – dragi Aug 28 '18 at 17:21
5

Destructuring is basically syntatic sugar Some Eslint configurations prefer it (which I'm guessing is your case).

It's basically declaring the values and making them equal to the bit of syntax you don't want to repeat, for Ex, given react props:

this.props.house, this.props.dog, this.props.car

destructured --->

 const { house, dog, car } = this.props;

So now you can just use house, or dog or whatever you want. It's commonly used with states and props in react, here is more doc about it, hope it helps. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

Kay
  • 105
  • 3
0

This is problem with your onChange method. Try something like this:

onChange = e =>
    this.setState(prevState => ({
        data: { ...prevState.data, [e.target.name]: e.target.value }
    }));

And look at section "State Updates May Be Asynchronous" from https://reactjs.org/docs/state-and-lifecycle.html

Maciej Wojsław
  • 403
  • 2
  • 10
  • it will throw an error, check [this answer](https://stackoverflow.com/questions/45483492/accessing-event-target-inside-callback-in-react/45483658#45483658) for more details. – Mayank Shukla Aug 28 '18 at 11:01