Too long to look at the version 👉 directly jump to find the reason

Bug emersion

In a form, the user modifies the data previously filled in, and the original data is stored in Redux. After modification, the user will update the data in ReDUx. The save button can be clicked only when the content is modified, otherwise the save button will be in the grey state. Data to see if there is modified by componentWillReceiveProps redux, old and new data in diff operation (with lodash isEqual), can be said to be very common scenario. However, the test students have been feedback, save button after clicking is still in clickable state, not to say more, check the bug 😑

To find the reason

Here I have to make fun of the fact that the code file in question is very lengthy, with more than 2000 lines, making it very inconvenient to find the problem

Because the problem is the state of the button, and the state of the button is diff through the old and new data, so the first point that comes to mind must be the data problem, whether there is a problem with the data transmitted to the interface, or the data returned by the interface. After checking, the data is ok, of course, this is expected. And if you look at the data in Redux which is the most recent data. Ah, continue to check bai 😣

Since there is no problem with the data, then it must be diff problem, of course can not rule out lodash problem, but as gitLab 40K + star library is quite reliable, it can not be found in the source code of isEqual. Because we are placed in componentWillReceiveProps diff operation, so inevitable printed last time and the value of the props, and sure enough, problems appear, ComponentWillReceiveProps enclosing the props and next. The props of value is the same, must have the cause of the bug in this for certain. But, this is very strange, because we all know this. In the componentWillReceiveProps props of value and the next. The value of the props are normally is different, so what reason is caused, take this question, opened the react website 🤔

Find the problem

After some searching, I found this passage

React will pass props down to avoid any other problems or deep comparisons. When a reference type is modified, it is still the same instance, even though the content has been modified. React will pass props down to avoid any other problems.

So could it be when we are to process the data for form, modify the content of the reference data, triggering the react triggered componentWillReceiveProps, so when redux to save the new data to trigger componentWillReceiveProps, This.props has been updated, and the code modifs the value of state without passing setState.

The error code

import React from "react";
import { connect } from "react-redux";
import { illegalChangeState } from ".. /.. /actions/index";

class Test extends React.Component {
  constructor(. props) {
    super(... props);this.state = {
      obj: {
        a: 0,}}; }componentWillReceiveProps(nextProps) {
    // This. Props is the same as nextProps
    console.log(this.props);
    console.log(nextProps);
  }
  componentDidMount() {
    this.setState({
      obj: this.props.obj,
    });
  }
  changeState = () = > {
    const { obj } = this.state;
    // Change state directly
    obj.a = 2;
    this.props.illegalChangeState(obj.a);
  };

  render() {
    return <div onClick={this.changeState}>{this.state.obj.a}</div>; }}const mstp = (state) = > {
  return {
    obj: state.obj,
  };
};

export default connect(mstp, { illegalChangeState })(Test);

Copy the code

Knowing the reason, the problem will be solved naturally.