React组件修改类实例属性后setState未触发重渲染该如何解决
问题原因
- 首先你的代码存在基础拼写错误:自定义类定义时命名为小写
persons,实例化时调用的是大写Persons,需要先统一类名,否则会直接抛出引用错误。 - React的状态更新默认做浅比较,如果新传入的状态值和旧状态值是同一个引用地址的对象/数组,React会认为状态没有发生变化,就不会触发重渲染。
- 你这里的
persons.list始终是同一个对象引用:初始化persons实例的时候传入的是personsList状态对象,后续调用addPerson只是在原有对象上新增属性,没有创建新的对象,所以调用setPersonsList的时候传入的还是原来的对象引用,React判断状态无变化,跳过渲染。 - 你第二种写法
setPersonsList(persons.getPersons)是错误用法:你传入的是方法本身没有调用,相当于把状态值修改为了getPersons函数本身,自然也不会触发预期的更新。
解决方案
方案1:修改addPerson逻辑返回新对象
修改自定义类的addPerson方法,不修改原对象,而是返回新的对象:
// 统一类名为大写规范写法 class Persons { constructor(list = {}) { this.list = list } getPersons() { return this.list } addPerson(someId, person) { // 这里创建新对象,不修改原有引用 this.list = { ...this.list, [someId]: person } } }
组件调用的时候直接传修改后的list即可:
// ... const [personsList , setPersonsList] = useState({}) const persons = new Persons(personsList) // 注意把someId作为参数传入,避免全局变量污染 persons.addPerson('1', {name: "Mike"}) setPersonsList(persons.list) //..
方案2:setState的时候手动创建新对象传入
如果不想改自定义类的逻辑,也可以在更新状态的时候手动生成新对象,让React识别到引用变化:
persons.addPerson('1', {name: "Mike"}) // 解构原有属性到新对象里,生成新的引用 setPersonsList({...persons.list})
方案3:使用immer处理复杂嵌套对象(可选)
如果项目中经常要操作复杂嵌套对象,可以引入immer来生成不可变数据,写法更简便,不容易出错:
import { produce } from 'immer' // ... persons.addPerson('1', {name: "Mike"}) setPersonsList(produce(persons.list, draft => {}))
内容的提问来源于stack exchange,提问作者Khaled Developer
相关产品推荐
相关产品推荐

