Sigi framework document
Introduction
Basic
Recipes
FAQ
基本概念
深入
常见问题类型推断Effect 结束回调

FAQ

类型推断

在编写 Effect/SSREffect 逻辑的时候,如果这个 Effect 包含触发自身的逻辑或者多个 Effect 互相依赖, 则会出现类型推断失败的情况:

Example in CodeSandbox

import { EffectModule, Module, ImmerReducer, Effect } from "@sigi/core";
import { Draft } from "immer";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
export interface CountState {
count: number;
}
@Module("Count")
export class CountModule extends EffectModule<CountState> {
defaultState = {
count: 0,
};
@ImmerReducer()
set(state: Draft<CountState>, payload: number) {
state.count = state.count + payload;
}
@Effect()
addLeastFive(payload$: Observable<number>) {
return payload$.pipe(
map((payload) => {
if (payload < 5) {
return this.getActions().addLeastFive(payload + 1);
}
return this.getActions().set(payload);
})
);
}
}

此时需要显示标注 Effect 的返回值:

- import { EffectModule, Module, ImmerReducer, Effect } from '@sigi/core'
+ import { EffectModule, Module, ImmerReducer, Effect, Action } from '@sigi/core'
- addLeastFive(payload$: Observable<number>) {
+ addLeastFive(payload$: Observable<number>): Observable<Action> {

Effect 结束回调

有几种常见的业务场景需要在 Effect 结束后执行 回调:

成功/失败后展示消息

取决于展示消息的 API,我们可以用数据驱动/副作用两种方式来实现这个需求:

CodeSandbox effects callback side effect

import { Module, EffectModule, Reducer, Effect, Action } from "@sigi/core";
import { Observable, of } from "rxjs";
import {
exhaustMap,
takeUntil,
map,
tap,
startWith,
catchError,
} from "rxjs/operators";
import { message } from "antd";
import { HttpClient } from "./http.service";
interface AppState {
list: string[] | null | Error;
}
@Module("App")
export class AppModule extends EffectModule<AppState> {
defaultState: AppState = {
list: [],
};
constructor(private readonly httpClient: HttpClient) {
super();
}
@Reducer()
cancel(state: AppState) {
return { ...state, ...this.defaultState };
}
@Reducer()
setList(state: AppState, list: AppState["list"]) {
return { ...state, list };
}
@Effect()
fetchList(payload$: Observable<void>): Observable<Action> {
return payload$.pipe(
exhaustMap(() => {
return this.httpClient.get(`/resources`).pipe(
tap(
() => {
message.success("Got response");
},
(e) => {
message.error(e.message);
}
),
map((response) => this.getActions().setList(response)),
catchError((e) => of(this.getActions().setList(e))),
startWith(this.getActions().setList(null)),
takeUntil(this.getAction$().cancel)
);
})
);
}
}

CodeSandbox effects callback state driven

import "reflect-metadata";
import "antd/dist/antd.css";
import React, { useState, useCallback } from "react";
import { render } from "react-dom";
import { useModule } from "@sigi/react";
import { initDevtool } from "@sigi/devtool";
import { Modal } from "antd";
import { AppModule } from "./app.module";
function App() {
const [{ list }, dispatcher] = useModule(AppModule);
const [modalVisible, setModalVisible] = useState(true);
const onFetchList = useCallback(() => {
setModalVisible(true);
dispatcher.fetchList();
}, [dispatcher, setModalVisible]);
const onClose = useCallback(() => {
setModalVisible(false);
}, [setModalVisible]);
const loading = !list ? <div>loading</div> : null;
const title =
list instanceof Error ? (
<>
<Modal
title="fail"
visible={modalVisible}
onOk={onClose}
onCancel={onClose}
>
<p>{list.message}</p>
</Modal>
<h1>{list.message}</h1>
</>
) : (
<h1>Hello CodeSandbox</h1>
);
const listNodes = Array.isArray(list)
? list.map((value) => <li key={value}>{value}</li>)
: null;
return (
<div>
{title}
<button onClick={onFetchList}>fetchList</button>
<button onClick={dispatcher.cancel}>cancel</button>
{loading}
<ul>{listNodes}</ul>
</div>
);
}
const rootElement = document.getElementById("app");
render(<App />, rootElement);
initDevtool();