FAQ
Type Infer
When you are writing Effect/SSREffect
logic, if the Effect
emit an Action
which infer from itself, or some Effects
circular dependents the others, Type infer
in TypeScript may fail.
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);}));}}
In this scenario, you need give the Effect
a Return Type
explicit:
- 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 end callback
There are some cases you may need run callback
after Effect end:
Show message after Success/Failure
Depends on the API which show message, we could use Data driven/Side effect ways to implement this requirement:
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 ? (<><Modaltitle="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();