什么时候在 mobx 中使用 computed/observables

When to use computed/observables in mobx

我觉得我了解了大部分的 mobx,但我想澄清一些事情。我有一个带有一些可观察对象的商店,其核心是一个对象数组(打字稿):

class ClientStore {
    constructor() {
        this.loadClients();
    }

    @observable private _clients: IClient[] = [];
    @computed get clients() {
        return this._clients;
    }
    @observable isFetching: boolean = false;
    @observable sortField: 'title' | 'modified' = 'modified';
    @observable sortDescending: boolean = true;

    getClientByUrlName(urlName: string): IClient {
        return this._clients.find(c => c.urlName === urlName);
    }
etc...

我的问题是最后一个函数 - getClientByUrlName。由于这是从可观察对象中发现的,因此使用该函数的任何 @observer 反应组件都会正确重新呈现。这是惯用的 mobx 吗?感觉应该是一个计算值。我应该在要使用它的组件中创建一个计算值吗?

//import singletone ClientStore
class ClientDetailsView extends React.Component<{params:{urlName:string}}, void> {

    @computed get client() {
        return ClientSotre.clients.find(c => c.urlName === this.props.params.urlName);
    }

...rest of react component

我正在寻找最佳实践和陷阱。感谢任何帮助。

*编辑修复代码示例错误

原则上 @computed 是一个简单的指令,它告诉 MobX:"this value could be cached until any of the observables that is used changes"。所以实际上它们总是可以被排除在外,这只是意味着您的应用程序将重新计算更多,但不会改变结果。

因此,如果您缺少 @computed 原则上在大多数情况下都不是问题的功能。如果是,您可以使用 createTransformer 它接受一个参数函数并构建一个(自清理)计算值的记忆缓存。但它有点复杂,所以实际上你在 ClientDetailsView 中引入计算 属性 的解决方案更好。我确实会建议这样做,只要你有一个很好的地方来放置计算出的 属性(在这种情况下需要它的组件)

任何想知道如何在 Functional Components.

中使用 Computed 的人

你必须结合来自 react 的 useMemo() 和来自 mobx 的 computed():

TypeScript

import {useMemo} from 'react';
import {computed, IComputedValueOptions} from 'mobx';

// changes to "options" argument are ignored
export default function useComputed<T>(func: () => T, options?: IComputedValueOptions<T>, deps?: DependencyList)
{
    return useMemo(() => computed(func, options), deps ?? []).get();
}

JavaScript

import {useMemo} from 'react';
import {computed} from 'mobx';

// changes to "options" argument are ignored
export default function useComputed(func, options)
{
    return useMemo(() => computed(func, options), deps ?? []).get();
}

例子

export default observer(function MyComponent()
{
    const sum = useComputed(() => observableA.myValue + observableB.myValue);
    return <div>{sum}</div>
})

道​​具应该依赖

export default observer(function MyComponent({observableA, observableB})
{
    const sum = useComputed(() => observableA.myValue + observableB.myValue, null, [observableA, observableB]);
    return <div>{sum}</div>
})

如果您不将道具放在 deps 中,那么 computed() 将继续使用旧道具并且永远不会更新。

不要忘记用 observer() 包装您的组件,否则它不会对更改做出反应!