redux-saga
redux中文版文档
redux-saga中文文档
在线请求api
redux-devtools-extension 调试工具 – 使用 redux-devtools-extension 查看 Redux 中状态变化
本文的案例是用的redux和redux-saga,这里的案例是用的redux、redux-saga
概述
redux-saga 是 redux 一个中间件,用于解决异步问题。
es6 Generator
解决地狱回调问题,通过 yield 关键字,可以让函数的执行流挂起。
使用在线工具验证:https://jsbin.com/musedihito/edit?js,console
参考:
https://blog.csdn.net/tcy83/article/details/80427195
Redux -saga 案例流程
main.js
首先在main.js里引入createStore 和 createSagaMiddleware, 并创建saga中间件和store
import * as React from 'react'
import ReactDOM from 'react-dom'
import { createStore, applyMiddleware } from 'redux'; // store、中间件
import createSagaMiddleware from 'redux-saga'; // ***1.saga引入createSagaMiddleware***
import Counter from './components/Counter'
import reducer from './reducers'
import rootSaga from './sagas'
// ***2.创建saga中间***件
const sagaMiddleware = createSagaMiddleware()
const store = createStore(reducer, applyMiddleware(sagaMiddleware))
sagaMiddleware.run(rootSaga)
const action = type => store.dispatch({ type })
function render() {
ReactDOM.render(
<Counter
value={store.getState()}
onIncrement={() => action('INCREMENT')}
onDecrement={() => action('DECREMENT')}
onIncrementIfOdd={() => action('INCREMENT_IF_ODD')}
onIncrementAsync={() => action('INCREMENT_ASYNC')}
/>,
document.getElementById('root'),
)
}
render()
store.subscribe(render)
components/Counter.js
import * as React from 'react'
import PropTypes from 'prop-types'
const Counter = ({ value, onIncrement, onIncrementAsync, onDecrement, onIncrementIfOdd }) => (
<p>
Clicked: {value} times <button onClick={onIncrement}>+</button> <button onClick={onDecrement}>-</button>{' '}
<button onClick={onIncrementIfOdd}>Increment if odd</button>{' '}
<button onClick={onIncrementAsync}>Increment async</button>
</p>
)
Counter.propTypes = {
value: PropTypes.number.isRequired,
onIncrement: PropTypes.func.isRequired,
onDecrement: PropTypes.func.isRequired,
onIncrementAsync: PropTypes.func.isRequired,
onIncrementIfOdd: PropTypes.func.isRequired,
}
export default Counter
什么是prop-types?
reducers/index.js
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'INCREMENT_IF_ODD':
return (state % 2 !== 0) ? state + 1 : state
case 'DECREMENT':
return state - 1
default:
return state
}
}
saga/index.js
/* eslint-disable no-constant-condition */
import { put, takeEvery, delay } from 'redux-saga/effects'
export function* incrementAsync() {
yield delay(1000)
yield put({ type: 'INCREMENT' })
}
export default function* rootSaga() {
yield takeEvery('INCREMENT_ASYNC', incrementAsync)
}
简单理解 ‘redux-saga/effects’ 中的几个关键字:fork,call, put,takeEvery,takeLatest,all
fork() 创建一个新的进程或者线程,并发发送请求
关键代码:
function* user() {
yield takeEvery('FETCH_REQUEST', fetch_user); // 监听 FETCH_REQUEST action
}
// 并发发送请求
function* fetch_user() {
const [users, todos] = [
yield fork(fetchResource, 'https://jsonplaceholder.typicode.com/users'),
yield fork(fetchResource, 'https://jsonplaceholder.typicode.com/todos')
]
}
function* fetchResource(resource) {
const data = yield call(axios.get, resource);
// 获取 call 数据,触发成功后的 action
yield put({ type: 'FETCH_SUCESS', uu: data });
}
call() 发送 api 请求
put() 发送对应的 dispatch,触发对应的 action
takeEvery() 监听对应的 action 每一次 dispatch 都会触发
例如:点击一个新增的按钮,2s 后触发新增动作,在2s内不断点击按钮,这时候,每一次点击,都是有效的。
yield takeEvery(‘FETCH_USER’, fetch_user);
其中, FETCH_USER是action, fetch_user是监听到这个action后需要执行的动作。
takeLatest() 监听对应的 action只会触发最后一次 dispatch
例如:点击一个新增的按钮,2s 后触发新增动作,在2s内不断点击按钮,这时候,只有最后一次点击是有效的。
yield takeLatest(‘FETCH_USER’, fetch_user);
参数所指同takeEvery()