Redux
React-Redux
1
2
3
4
5
6
7
8
<Provider store = {store}>
<App />
<Provider>
// 让所有组件都能够访问到Redux中的数据
connect
mapStateToProps
mapDispatchToProps
Redux-Saga: 创建saga middleware 并且将其连接至redux store
1
2
3
4
const store = createStore(
reducer,
applyMiddleware(createSagaMiddleware(helloSaga)) // 使用 applyMiddleware 将 middleware 连接至 Store
)
Sagas 被实现为 Generator functions,它会 yield 对象到 redux-saga middleware。 被 yield 的对象都是一类指令,指令可被 middleware 解释执行。当 middleware 取得一个 yield 后的 Promise,middleware 会暂停 Saga,直到 Promise 完成。
1
2
3
4
5
作用:决定什么时候发起dispatch
解决在reducer纯函数不能处理异步方法,需要中间件处理
组件中发生的action后,在进入reducer之前需要完成一个异步任务,
比如发送ajax请求后拿到数据后,再进入reducer,显然原生的redux是不支持这种操作的
put 阻塞的effect, 可以看作是redux的dispatch函数, 发送action的effect, 每个put(action)就相当dispatch(action)出去,reducer边接收到相应的action.type就会对数据进行相应的操作,最后通过react-redux的connect回到视图中,完成了一次数据驱动视图,
call 阻塞的effect,类似于async的await,只有当前任务成功才往下继续执行
take 阻塞的effect, 主要用来监听action.type的,只有监听到了,才会继续往下执行
takeEvery takeEvery就像一个流水线的洗碗工,过来一个脏盘子就直接执行后面的洗碗函数,一旦你请了这个洗碗工他会一直执行这个工作,不会停止接盘子的监听过程和触发洗盘子函数 这个洗碗工可以无限次的接受脏盘子的action,也不会停止洗盘子,所以你没办法指定让他具体洗盘子 区别: 监听一个action, 只要action被触发就执行
- takeLatest takeLatest是在他的程序没运行完时,再次运行时,会取消它的上一个任务;而takeEvery则是运行都会fork一个新的任务出来,不会取消上一个任务;所以,用takeLatest来处理重复点击的问题
1 2 3 4 5 6 7 8 9 10
const takeLatest = (patternOrChannel, saga, ...args) => fork(function*() { let lastTask while (true) { const action = yield take(patternOrChannel) if (lastTask) { yield cancel(lastTask) // cancel is no-op if the task has already terminated } lastTask = yield fork(saga, ...args.concat(action)) } })
- fork 非阻塞的effect, 与call相似,都是用来调用其他函数,
返回一个任务,这个任务是可以被取消的, call返回的就是它执行的正常返回结果
- cancel 取消任务,配合fork适合 ```bash const task = yield fork(getData, action); yield take(“CANCEL_REQUEST”); yield cancel(task);
*getData(action) { try(){} catch(){} finally(){ yield cancelled() } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#### fork & spawn
```markdown
const { delay, runSaga } = require("redux-saga");
const fetch = require("node-fetch");
const { fork, spawn, call, put} = require("redux-saga/effects");
function* fetchResource(resource) {
console.log(`Fetch ${resource} start`);
const response = yield call(fetch, "https://jsonplaceholder.typicode.com" + resource);
const text = yield call(response.text.bind(response));
console.log(`Fetch ${resource} end`);
}
function* fetchAll() {
console.log("Fork or Spawn start");
// this is pseudo code, I mean here that you can use either
// fork or spawn, check results below
const task1 = yield fork||spawn(fetchResource, "/posts/1");
const task2 = yield fork||spawn(fetchResource, "/posts/2");
console.log("Fork or Spawn end");
}
function* main() {
console.log("Main start");
yield call(fetchAll);
console.log("Main end");
}
runSaga({}, main);
// RESULTS WITH FORK(): | RESULTS WITH SPAWN():
// |
// Main start | Main start
// Fork start | Spawn start
// Fetch /posts/1 start | Fetch /posts/1 start
// Fetch /posts/2 start | Fetch /posts/2 start
// Fork end | Spawn end
// Fetch /posts/2 end | Main end <--
// Fetch /posts/1 end | Fetch /posts/2 end
// Main end <-- | Fetch /posts/1 end