typescript NGXS -从父状态访问子状态

wwtsj6pe  于 2023-10-22  发布在  TypeScript
关注(0)|答案(2)|浏览(110)

我有亲子状态:

@State({
     name: 'parent',
     default: { parentProp : 'foo' },
     children: [
        ChildState,
     ]
}) class ParentState {}

@State({
     name: 'child',
     default: { childProp: 'bar' },
}) class ChildState {}

然后在父状态下的操作中,我想从子状态中获取状态。有没有一种方法可以在一个动作处理程序中做到这一点,在这一点上,我不知道如何做到这一点,因为动作处理程序只有StateContext和动作负载?

enxuqcxy

enxuqcxy1#

似乎我可以做一些事情,

const child = <ChildStateModel>this.store.selectSnapshot(state => state.child);

或只是使用

@Action(context: StateContext<ChildStateModel>, action: any)

如果只需要访问孩子

wpx232ag

wpx232ag2#

你可以用substate的名字给你的模型接口/类型添加可选的属性。这样,您就不必在@State装饰器中填充default:,并且仍然可以从父级访问子状态。
我是这样做的:

/*
please note that this is only example ;)
Substate with only one property probably isnt what you need...

Also please note that I am not using interfaces but types 
(its not called InterfaceScript, is it? ;) ) - should be the same with interfaces 
*/

// name of sub-state to keep typing in our state models / contexts / etc.
export const selecteBookStateName = 'selectedBook'; 
export type Book = { title: string };

export type LibraryStateModel = { 
  books: Book[];
  loading: boolean;
  // this is the line with magic
  // `[variable]: type` means "use value of variable as property name"
  // `foo?: type` means "property foo is optional"
  // Combined, we use this as "optional property named value of selecteBookStateName"
  [selecteBookStateName]?: SelectedBookStateModel;
};
export type SelectedBookStateModel = { model: Book | null; };

// helper state operator so we dont have to care about 
// actual value of `selecteBookStateName` and still keep code type safe
export function patchSelectedBookSubState(
  selectedRepository: Partial<SelectedBookStateModel>
): StateOperator<LibraryStateModel> {
  return patch({
    [selecteBookStateName]: patch<SelectedBookStateModel>(selectedRepository),
  });
}

@State<LibraryStateModel>({
  name: 'library',
  defaults: {
    books: [],
    loading: false,
    // note that I did not specify "selectedBook" here - its optional, I dont have to.
  },
  children: [SelectedBookState],
})
@Injectable()
export class LibraryState {

@Action(SelectBook)
selectBook(ctx: StateContext<LibraryStateModel>, action: SelectBook)
  const state = ctx.getState();

  // we should expect substate to be undefined
  // it should never be, but we lost this info when we make substate optional in our library type.
  // I didnt solve this (And I dont really care)
  const current: SelectedBookState | undefined = state.selectedBook?.model;
  // another way to access the substate.
  const current2: SelectedBookState | undefined = state[selecteBookStateName]?.model;

  // NGXS doc told you to never use setState or you will erase the context of substate.
  // this is not the case, we returned `patch()` from our helper state operator.
  ctx.setState(patchSelectedBookSubState(action.payload));
}

@State<SelectedBookStateModel>({
  // constant from before.
  name: selecteBookStateName, 
  defaults: {
    model: null
  },
})
@Injectable()
export class SelectedBookState {
  @Action(BorrowBookOrSomething)
  borrowBook(ctx: StateContext<SelectedBookStateModel>)
  {
    ...
  }
}

相关问题