React组件中props意外被修改问题求助
你遇到的是React开发里非常典型的意外篡改Props问题——虽然你没有直接编写this.props.data = xxx这类代码,但Props还是被悄悄修改了。核心原因几乎都是引用类型数据的浅拷贝/直接修改导致的,下面给你一步步排查的思路:
1. 先检查构造函数的displayData赋值
你在构造函数里直接把this.props.data赋值给了state.displayData:
displayData: this.props.data,
如果props.data是数组或对象这类引用类型,这只是复制了数据的内存引用,而非创建新的独立副本。后续任何对displayData的直接修改(比如用splice、pop改数组,或者修改对象属性),都会直接影响到原props.data。
解决办法是创建数据的独立副本:
- 如果是数组:用展开运算符做浅拷贝
[...this.props.data] - 如果是对象:
{...this.props.data} - 如果是嵌套的复杂结构(比如对象里包含数组):用深拷贝,比如
JSON.parse(JSON.stringify(this.props.data))(注意这种方法不支持函数、Symbol等特殊类型)
修改后的构造函数示例:
constructor(props) { super(props); // 深拷贝props.data,切断与原数据的引用关联 const copiedData = JSON.parse(JSON.stringify(props.data)); this.state = { visibleColumns: ["NAME", "CALLS", "EMAILS", "CHATS", "NEW1", "NEW2"], displayData: copiedData, }; this.handleSave = this.handleSave.bind(this); this.getVisible = this.getVisible.bind(this); }
2. 排查getVisible方法(你提到但未粘贴的代码)
这个方法大概率是用来根据visibleColumns过滤数据的,如果它使用了会修改原数组的方法(比如splice、shift、sort),而不是返回新数组,就会间接篡改props.data。
正确的做法是使用返回新数组的方法,比如filter:
getVisible() { // 返回新数组,不修改原displayData return this.state.displayData.filter(item => { return this.state.visibleColumns.includes(item.columnKey); // 假设你的数据结构有columnKey字段 }); }
3. 检查子组件对props.data的操作
你提到props.data被传给了子组件用于显示列,要确认子组件里有没有直接修改这个Props:比如子组件里写了props.data.splice(...)、props.data[0].name = "xxx"这类代码。
React要求Props是只读的,子组件如果需要修改数据,应该通过父组件传递的回调函数,让父组件更新自己的State,再把新的State作为Props传给子组件。
4. 排查其他可能修改数据的地方
检查组件的其他生命周期方法(比如componentDidUpdate)、事件处理函数,有没有直接或间接操作props.data或state.displayData的引用。比如:
- 是否在某个地方用了
Object.assign但只做了浅拷贝? - 是否有第三方库(比如表格组件)默认修改传入的数据?
5. 长期解决方案:使用不可变数据工具
如果经常遇到这类引用类型修改的问题,可以考虑用工具来强制数据不可变:
- Immer:允许你用" mutable "的写法编写代码,最终自动生成不可变的新数据,学习成本低
- Immutable.js:提供一套不可变的数据结构,彻底避免引用修改问题
内容的提问来源于stack exchange,提问作者Bishonen_PL

