UNPKG

utquidem

Version:

The meta-framework suite designed from scratch for frontend-focused modern web development.

172 lines (139 loc) 4.96 kB
--- sidebar_position: 4 --- # effects :::info 补充信息 **effects** 用于封装各种副作用函数。 ::: :::tip 提示 - `@modern-js-reduck/plugin-effects` 内置于 Modern.js,默认开启。 - 可通过 [**modern.config.js**](#) 关闭插件。 ::: [**actions**](./model_#actions) 是用来同步修改 **state** 的(纯函数、无副作用)。但应用开发的过程中,会有大量的**异步请求或者封装某些操作**等各种副作用的调用,所以这里将各种副作用的函数(**Effect Handler**)封装在 **effects** 模块。 ## 示例 **Effect Handler** 函数类型包括 3 种: - [**VoidEffect**](#voideffect):返回类型为 **void**。 - [**PromiseEffect**](#promiseeffect):**async/await** (Promise) 类型。 - [**ThunkEffect**](#thunkeffect):**redux-thunk** 中间件支持的 **thunk** 类型。 ```ts title="类型签名" type VoidEffect = (...args: any[]) => void; type PromiseEffect = (...args: any[]) => Promise<any>; type ThunkEffect = (...args: any[]) => (dispatch?, getState?) => void | Promise<any>; interface ModelEffects { [effectKey: string]: VoidEffect | PromiseEffect | ThunkEffect, } ``` ### VoidEffect 副作用调用并不只是异步请求,比如还有 localStorage、DOM 操作等,这些操作没有返回,那么也无需进行 pending、fulfilled、rejected 等阶段的处理。 对于不需要进行 pending、fulfilled、rejected 等阶段处理的异步请求也可以选择不 return。 ```tsx title="示例" import { model, useModel } from '@modern-js/runtime/model'; const fooModel = model('foo').define((_, { use }) => { return { state: { value: 'foo' }, effects: { async load() { const resp = await fetch('xxxx'); const [, actions] = use(fooModel); actions.setValue(resp.data); }, setLocalStorage(key: string, value: string) { localStorage.set(key, value); } } } }); function App() { const [, actions] = useModel(fooModel); return <button type="button" onClick={async () => { await actions.load(); actions.setLocalStorage(); }}>go</button> } ``` ### PromiseEffect 一个异步请求完成前后通常有三种状态 pending(请求中)、fulfilled(请求成功)、rejected(请求失败)。 所以当触发一个 **effect dispatcher** 时,其内部就会在请求的不同阶段自行调用 `actions.load.pending`(请求中)、`actions.load.fulfilled`(请求成功调用)、`actions.load.rejected`(请求失败调用)这几个 **action dispatcher**。 所以为了正常处理这这三个状态对应的结果,我们需要编写相应 **pending、fulfilled、rejected** 阶段的 **action handler**。在相应的 **action handler** 函数中处理副作用函数所触发的不同阶段。 ```tsx title="示例" import { model, useModel } from '@modern-js/runtime/model'; const fooModel = model('foo').define((_, { use }) => { return { state: { items: [{ text: 'Use Reduck', completed: false }], isPending: false, error: null }, actions: { load: { pending(state) { state.isPending = true; state.error = null; }, fulfilled(state, payload: Array<{ text: string; completed: boolean }>) { state.items = payload; state.isPending = false; }, rejected(state, error: any) { state.error = error; state.isPending = false; } } }, effects: { async load() { return await [ { text: 'foo', completed: false}, { text: 'bar', completed: true } ] }, } } }); function App() { const [, actions] = useModel(fooModel); return <button type="button" onClick={async () => { await actions.load(); actions.setLocalStorage(); }}>go</button> } ``` ### ThunkEffect **redux-thunk** 中间件也是为了解决异步函数诞生的。所以这里也支持了 Thunk 类型函数 :::tip 提示 支持返回值为 `Promise<any>`,当返回值为 Promise 时,效果等同于 PromiseEffect,也会主动调用各个状态的 action dispatcher,这样无需手动调用了。 ::: ```tsx title="示例" import { model, useModel } from '@modern-js/runtime/model'; const fooModel = model('foo').define((_, { use }) => { return { state: { value: 'foo' }, effects: { loadThunk: (...args) => (dispatch, getState) => { dispatch.todo.load.pending() /* 等价于 dispatch({ type: 'TODO/LOAD/PENDING' }) */ fetch('xxxx') .then(data => context.actions.load.fulfilled(data)) .catch(err => context.actions.load.rejected(err)) } } } }); function App() { const [, actions] = useModel(fooModel); return <button type="button" onClick={() => { actions.load(); }}>go</button> } ```