MobX - 当我可以使用 `inject` 将数据注入 React 组件时,为什么我应该使用 `observer`

MobX - Why should I use `observer` when I could use `inject` when injecting data into a React component

MobX 文档建议我应该在所有组件上使用 observer。但是,通过使用注入,我可以更精细地控制哪些数据导致我的组件重新渲染。

我的理解是,对于 observer,上次渲染中所有访问的 observable 的更改将导致重新渲染,即使 observable 嵌套在数据存储的深处,而 inject 仅当注入器函数中访问的可观察对象发生变化时才重新渲染。

例如:

class Store{
  @observable data = {
    nestedData: {
      deepData: 'my_data'
    }
  }
}

const store = new Store();

... Assume the store is injected using <Provider /> component

// This will cause re-render when the data object changes
// for example: store.data = { new_data: 'new_data' }
@inject(stores => {
  return { data: stores.dataStore.data }; 
})
class MyComponent extends Component {  }

// This will re-render on change of the data object, but also
// on change of nestedData and deepData properties
@inject(stores => {
  return { data: stores.dataStore.data }; 
})
@observer
class MyComponent extends Component {  }

有人可以证实我对此的理解吗?

在我看来,最好只使用 inject,因为它可以让您有更多的控制权,并且可以防止不必要的重新渲染。如果数据嵌套很深,你可以创建一个计算的 属性 从深层结构中获取和准备数据,然后将 属性 注入组件。

有没有其他的benefits/drawbacks当一个比另一个使用时

我相信您的评估是正确的。为了清楚起见,让我尝试改写一下:

@observer 跟踪 render 使用了哪些可观察对象,并在这些值之一发生变化时自动重新渲染组件。

我们应该注意 render 使用的 @observable 值可能深深嵌套在给定的 prop 中,根据您的示例:

class Store{
  @observable data = {
    nestedData: {
      // changes to `deepData` would theoretically re-render any observer
      deepData: 'my_data' 
    }
  }
}

with observer, a change in all accessed observables in the last render will cause a re-render, even if the observable is nested deep in the data store

宾果!

尽管 observable 有一个怪癖,您稍后会看到...


另一方面,您有 @inject,它使组件(通过 props)可以使用由 Provider.

定义的特定数据结构

例如:

@inject('title')
class MyComponent extends React.Component {
    render() {
        return (<div>{this.props.title}</div>);
    }
}

const Container = () => (
    <Provider title="This value is passed as a prop using `inject`">
        <MyComponent />
    </Provider>
);

inject only re-renders when observables accessed in the injector function change.

宾果!

inject 只会在 prop 本身识别出变化时才会重新渲染。


这实际上是 shouldComponentUpdate() and a deep-comparison of props -- though observer seems to be far more efficientshouldComponentUpdate 相同的问题。

In my opinion, it's better to use only inject as it gives you more control, and can prevent unnecessary re-renders.

我不一定会走那么远...这完全取决于您的代码结构。

如果我这样修改你原来的例子:

class Store{
    @observable data = {
        nestedData: {}
    };

    constructor() {
        this.data.nestedData.deepData = 'my_data';
    }
}

...添加 deepData 实际上不会被视为可观察到的变化(即重新渲染),因为当我们最初标记 [= 时 属性 不存在29=] 作为一个可观察的值。所以这是一个问题。

另一种方法可能是做这样的事情:

class Person {
    @observable name = 'John Doe';
}

class Store{
    @observable data = null;

    constructor() {
        this.data = new Person();
    }
}

这允许您将可观察值分散到 类 —— 因此您可能仍想将 Store 注入组件(以访问 Store.data 但最终任何可观察到的变化来自更新 Person.