Sigi framework document
Introduction
Basic
Recipes
FAQ
基本概念
深入
取消处理 Loading/Error 状态在 AppState 的一个值中存储所有可能的状态StateSelector依赖替换Module 异步加载测试EffectModule 异步加载
常见问题

处理 Loading/Error 状态

处理 Effect 中类似 AJAX 请求的 loadingerror 状态是非常常见的需求。在这里我们推荐以下方式实现这个需求:

AppState 的一个值中存储所有可能的状态

通常来说,将所有状态拆分存储在 State 里是比较常见的处理方式,但是也是最繁琐的方式。更优雅的方法是将这些可能的状态都存储在一个值里面,TypeScript 的类型系统会保证你在各种状态下都能正确的渲染对应的组件:

Error/Loading 状态管理例子

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 { 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(() => {
console.info("Got response");
}),
map((response) => this.getActions().setList(response)),
catchError((e) => of(this.getActions().setList(e))),
startWith(this.getActions().setList(null)),
takeUntil(this.getAction$().cancel)
);
})
);
}
}
import { Injectable } from "@sigi/di";
import { Observable, timer, throwError } from "rxjs";
import { map } from "rxjs/operators";
@Injectable()
export class HttpClient {
get(_url: string): Observable<string[]> {
return Math.random() > 0.5
? throwError(new TypeError("Fail to fetch"))
: timer(3000).pipe(map(() => ["mock1", "mock2", "mock3"]));
}
}
import "reflect-metadata";
import React from "react";
import { render } from "react-dom";
import { useModule } from "@sigi/react";
import { initDevtool } from "@sigi/devtool";
import { AppModule } from "./app.module";
function App() {
const [{ list }, dispatcher] = useModule(AppModule);
const loading = !list ? <div>loading</div> : null;
const title =
list instanceof Error ? (
<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={dispatcher.fetchList}>fetchList</button>
<button onClick={dispatcher.cancel}>cancel</button>
{loading}
<ul>{listNodes}</ul>
</div>
);
}
const rootElement = document.getElementById("app");
render(<App />, rootElement);
initDevtool();