Redux Observable 懶人包

久違的 Redux Observable。

前置作業

參考範例:stackblitz

定義好 Epic 內要做的事情

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { getPosts, getPostsSuccess, getPostsFailed } from '../features/demoSlice'
import { switchMap, catchError, of, from, map } from 'rxjs'
import { ofType } from 'redux-observable'
import { API } from '../api'

export const getPostsEpic = (action$) =>
action$.pipe(
ofType(getPosts.type),
switchMap((action) =>
from(API.getPosts()).pipe(
map((response) => getPostsSuccess(response)),
catchError((error) => of(getPostsFailed(error.message)))
)
)
)

合併成單一支 RootEpic

1
2
3
4
5
6
7
8
9
10
11
12
import { combineEpics } from 'redux-observable'
import * as demoEpics from './demoEpics'

const combineEpicFunctions = (epics) => {
return epics.reduce((arr, epic) => {
return arr.concat(Object.keys(epic).map((key) => epic[key]))
}, [])
}

const epics = combineEpicFunctions([demoEpics]) // [getPostsEpic, ...]

export const rootEpics = combineEpics(...epics) // combineEpics 不接收 Array,要記得用 ... 來展開

建立 middleware 掛到 store 身上,並且讓 Epic 跑起來

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { configureStore } from '@reduxjs/toolkit'
import demoReducer from '../features/demoSlice'
import { rootEpics } from '../epics'
import { createEpicMiddleware } from 'redux-observable'

const epicMiddleware = createEpicMiddleware()

export const store = configureStore({
reducer: {
demo: demoReducer
},
// 1. 掛到 store 身上
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(epicMiddleware)
})

// 2. 把 epic 跑起來
epicMiddleware.run(rootEpics)

同時打多個 API:forkJoin

這個可以想成是 Promise.all,平常妳是這樣寫:

1
2
3
4
Promise.all([API.getPosts(), API.getTodos()]).then(([posts, todos]) => {
console.log('posts', posts)
console.log('todos', todos)
})

在 Rx 裡面用 forkJoin 是這樣寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export const getPostsEpic = (action$) =>
action$.pipe(
ofType(getData.type),
switchMap((action) =>
forkJoin([from(API.getPosts()), from(API.getTodos())]).pipe(
map(([posts, todos]) =>
getDataSuccess({
posts,
todos
})
),
catchError((error) => of(getDataFailed(error.message)))
)
)
)

Promise.all 是接收用 Array 組成的 Promise,而 forkJoin 則是接收用 Array 組成的 Observable,然後兩個都會拿到 [result1, result2, ...] 的結果。

先打 A 在打 B 的 API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
export const getPostsEpic = (action$) =>
action$.pipe(
ofType(getData.type),
switchMap((action) => {
// 先打 A
return from(API.getPosts()).pipe(
mergeMap((postsReponse) => {
console.log('A succeeded', postsReponse)
// 再打 B
return from(API.getTodos()).pipe(
map((todosReponse) => {
console.log('B succeeded', todosReponse)
return getDataSuccess({
posts: postsReponse,
todos: todosReponse
})
})
)
}),
catchError((error) => of(getDataFailed(error.message)))
)
})
)
RxJS 筆記 讓 API 打得更順手-React Query
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×