如何从 Mobx 可观察数组中删除一个元素,而不导致整个消费组件重新渲染?

How to remove an element from a Mobx observable array, without causing the entire consuming component to rerender?

假设我有一个 todoStore。它有一个通过 id 删除待办事项的操作。请注意,我尝试了过滤器和拼接:

export default class TodosStore {
    constructor() {
    makeAutoObservable(this)  
    }

    todos = [
        {
            id: 1,
            name: "name1",
            completed: true
        },
        {
            id: 15,
            name: "name2",
            completed: true
        },
        {
            id: 14,
            name: "name3",
            completed: true
        }
    ]

    removeTodo(id) {
        // this.todos = this.todos.filter(todo=>todo.id != id)

        for (let todo of this.todos) {
            if (todo.id == id) {
                const indexOf = this.todos.indexOf(todo)
                this.todos.splice(indexOf, 1)
            }
        }
    }    
};

消费 Todos 组件(注意我用观察者包装了 Todo):

import { combinedStores } from "."    
const ObservableTodo = observer(Todo);

export default observer(() => {
    const { todosStore } = combinedStores       

    return (
        <div >
          {todosStore.todos.map(todo=>{
              return(
                <ObservableTodo onDelete={()=>{todosStore.removeTodo(todo.id)}} onNameChange={(value)=>{todosStore.editTodoName(todo.id,value)}} key={todo.id} todo={todo}></ObservableTodo>
               )
            })}
        </div>
    )
})

简单的 Todo 组件:

export default ({todo,onNameChange,onDelete}) => {
    return (
        <div style={{padding:'10px',margin:'10px'}}>
            <p>ID: {todo.id}</p>
            <input onChange={(e)=>{onNameChange(e.target.value)}}  value={todo.name}></input>
            <p>Completed: {todo.completed ? 'true' : 'false'} <button onClick={onDelete} className="btn btn-danger">Delete</button></p>            
        </div>
    )
}

即使我清楚地改变(而不是构建一个新数组)商店中的 todos 数组,Todos 组件重新呈现(我通过 [=25= 看到它]), 每个剩余的 Todo 组件也是如此。

有什么办法吗?也许我的设置有什么问题吗?我正在使用最新的 Mobx(6) 和 mobx-react。

Todos 组件应该重新渲染,因为它依赖于 todos 数组内容(因为它 map 在它上面)。因此,当您通过添加或删除一些待办事项来更改 todos 内容时 - Todos 组件将重新呈现,因为它需要呈现新内容,新的待办事项列表。

每个 Todo 重新呈现,因为您没有用 observer 包装它。包装每个使用某种可观察状态的组件是一种很好的做法,Todo 显然是这样做的。

您更改了 todo 数组的 length,因此 map 函数开始运行。然后当您遍历元素时,您正在传递 new ObservableTodo 组件(onDeleteonChange)的属性,这将使 ObservableTodo 始终重新渲染。

即使组件是 Mobx observable,它仍然遵循“React 规则”,当 React 在组件属性中看到 new 引用时,它会渲染组件。