太長不看版 👉 直接跳到找到緣由javascript
一個表單裏,用戶對以前填寫的數據進行修改,原始數據存在redux裏,用戶修改後會把redux裏的數據進行更新,當內容有修改時保存按鈕才能夠點擊,不然保存按鈕處於置灰狀態,數據是否有修改是經過componentWillReceiveProps新舊redux中的數據diff操做(用的lodash的isEqual),能夠說是很常見的場景了。可是呢,測試同窗卻一直反饋,保存按鈕在點擊以後仍然處於可點擊的狀態,很少說了,查bug了😑java
這裏不得不吐槽一下咱們出現問題的代碼文件十分的冗長,有2000多行,查找問題很是不便react
由於是按鈕狀態的問題,而按鈕的狀態又是經過新舊數據diff的,因此想到的第一個點確定就是數據問題,是否是數據傳給接口有問題,或者接口返回的數據有問題,排查了一下,數據沒問題,固然這也是意料之中。再看一下redux中的數據也是最新的數據。哎,繼續查唄😣git
既然數據都沒有問題,那麼就必然是diff的問題了,固然不能排除lodash的問題,可是做爲gitlab中40k+ star的庫仍是至關可靠的,實在查不出問題了再翻一下isEqual的源碼。由於咱們的diff操做是放在componentWillReceiveProps中,因此不可避免的打印了上次和此次的props的值,果真,問題出現了,componentWillReceiveProps中this.props和next.props的值是同樣的,想必形成此次bug的緣由確定在這了。可是呢,這就很奇怪,由於咱們都知道componentWillReceiveProps中this.props的值和next.props的值一般狀況下是不同的,那麼是什麼緣由形成的呢,帶着這樣的疑問,打開了react官網🤔redux
一番查找後,我發現了這段話markdown
大體意思就是對於引用類型來講,當咱們修改裏面的內容時,儘管內容已經修改,可是仍是同一個實例,因此react無法判斷裏面的數據是否修改,因此,爲了不別的問題出現或者進行深比較,react會把props向下傳遞。gitlab
因此會不會是在咱們對錶單的數據進行處理時,修改了引用數據的內容,從而引起react觸發了componentWillReceiveProps,因此當redux保存新的數據時再觸發componentWillReceiveProps,此時this.props已經被更新了呢,這時再回頭看一下保存時的邏輯,果真裏面的代碼直接修改了state中的值而沒有經過setState。測試
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) {
// 下面不正當操做state致使這裏this.props和nextProps的值是同樣的
console.log(this.props);
console.log(nextProps);
}
componentDidMount() {
this.setState({
obj: this.props.obj,
});
}
changeState = () => {
const { obj } = this.state;
// 這裏直接修改了state
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);
複製代碼
知道了緣由以後,問題天然而然迎刃而解。ui