1

我的 NGXS 状态定义如下

export interface Project{
  _id:string,
  name:string
}

export class ProjectStateModel {
    projects: Project[];
}

@State<ProjectStateModel>({
    name: 'Projects',
    defaults: {
        projects: [{_id:'111', name:'Project 1'}, {_id:'222', name: 'Project 2'}]
    }
})
@Selector()
    static getAll(state: ProjectStateModel) {
        return state.projects;
    }

    @Selector()
    static getById(state: ProjectStateModel) {
        return (id) => {
            return state.projects.find(p => p._id === id);
        };
    }

    @Action(ProjectsAction.Add)
    add({ getState, patchState }: StateContext<ProjectStateModel>, { payload }: ProjectsAction.Add) 
    {
        const state = getState();
        patchState({
            projects: [...state.projects, ...payload]
        })
    }

它是一个非常直接的状态实现。该州默认有2个项目;2 个选择器,一个用于获取所有项目,另一个通过 id 获取,一个用于添加新项目的操作。

我正在使用其中一个组件中的状态,如下所示

export class ProjectDetailComponent{
    selectedPROJ: Project;
    selectedPROJ$: Observable<Project>;
    
    constructor(){
        this.selectedPROJ$ = this.store.select(ProjectState.getById)
                .pipe(map(filterFn => filterFn('111')));
        this.test = this.selectedPROJ$.subscribe(p => {
          console.log(p); //this get logged every time there is a change in state even though the project 111 hasn't changed
        })
    }
}

我面临的问题是每次我更新状态时(比如向状态添加一个新项目),即使从状态中选择的项目没有改变,通过 id 获取的选择器也会重新触发。

例如,在上面显示的代码中,我选择了带有 id 的项目111。如果我发送一个Add动作来添加一个新项目,选择器getById会重新触发。

NGSX 中是否有任何方法可以定义参数化选择器,仅当所选项目的状态发生变化时才会触发该选择器?

injectContainerState在 NGXS 文档中查看过,但不明白如何将它与这个参数化选择器一起使用。

4

1 回答 1

1

选择器将根据其选择器进行记忆。

@Selector() // <-- no selector injected 
static getById(state: ProjectStateModel)

由于上面的选择器没有对状态标记、状态类或其他选择器的任何引用,因此默认情况下,选择器将在每次状态更改时运行。选择器的强大之处在于您可以在它们的基础上创建细粒度的选择器。

另一种选择是使用动态选择器。基本上在需要时创建选择器并传入所需的参数。这是一个例子:

https://stackblitz.com/edit/ngxs-selectors-upgky4?file=src/app/app.component.ts

该示例没有显示最佳实践,并且非常粗糙。例如,您不能更改 id。但它确实向您展示了实现您想要的另一种方式。

很棒的资源:https ://www.youtube.com/watch?v=y3F99IsnNvI

于 2021-03-26T14:23:18.700 回答