class Foo extends Component { constructor(props){ super(props); } render(){ return( // 这样子渲染的其实就是state.bar的数据了 <div>this.props.foo</div> ) } } Foo = connect()(Foo); export default Foo;
然后这样就可以完成渲染了
mapDispatchToProps
这个单词翻译过来就是就是把各种dispatch也变成了props让你可以直接使用
const mapDispatchToProps = (dispatch) => { // 默认传递参数就是dispatch return { onClick: () => { dispatch({ type: 'increatment' }); } }; }
class Foo extends Component { constructor(props){ super(props); } render(){ return( <button onClick = {this.props.onClick}>点击increase</button> ) } } Foo = connect()(Foo); export default Foo;
组件也就改成了上边这样,可以直接通过this.props.onClick,来调用dispatch,这样子就不需要在代码中来进行store.dispatch了
react-redux的基本介绍就到这里了
如果按照原始的redux工作流程,当组件中产生一个action后会直接触发reducer修改state,reducer又是一个纯函数,也就是不能再reducer中进行异步操作;
而往往实际中,组件中发生的action后,在进入reducer之前需要完成一个异步任务,比如发送ajax请求后拿到数据后,再进入reducer,显然原生的redux是不支持这种操作的
这个时候急需一个中间件来处理这种业务场景,目前最优雅的处理方式自然就是redux-saga
核心讲解
1、Saga 辅助函数
redux-saga提供了一些辅助函数,用来在一些特定的action 被发起到Store时派生任务,下面我先来讲解两个辅助函数:takeEvery 和 takeLatest
takeEvery
takeEvery就像一个流水线的洗碗工,过来一个脏盘子就直接执行后面的洗碗函数,一旦你请了这个洗碗工他会一直执行这个工作,绝对不会停止接盘子的监听过程和触发洗盘子函数
例如:每次点击 按钮去Fetch获取数据时时,我们发起一个 FETCH_REQUESTED 的 action。 我们想通过启动一个任务从服务器获取一些数据,来处理这个action,类似于
window.addEventLister('xxx',fn)
当dispatch xxx的时候,就会执行fn方法,
首先我们创建一个将执行异步 action 的任务(也就是上边的fn):
// put:你就认为put就等于 dispatch就可以了; // call:可以理解为实行一个异步函数,是阻塞型的,只有运行完后面的函数,才会继续往下; // 在这里可以片面的理解为async中的await!但写法直观多了! import { call, put } from 'redux-saga/effects' export function* fetchData(action) { try { const apiAjax = (params) => fetch(url, params); const data = yield call(apiAjax); yield put({type: "FETCH_SUCCEEDED", data}); } catch (error) { yield put({type: "FETCH_FAILED", error}); } }
然后在每次 FETCH_REQUESTED action 被发起时启动上面的任务,也就相当于每次触发一个名字为 FETCH_REQUESTED 的action就会执行上边的任务,代码如下
import { takeEvery } from 'redux-saga' function* watchFetchData() { yield* takeEvery("FETCH_REQUESTED", fetchData) }
注意:上面的 takeEvery 函数可以使用下面的写法替换
function* watchFetchData() { while(true){ yield take('FETCH_REQUESTED'); yield fork(fetchData); } }
takeLatest
在上面的例子中,takeEvery 允许多个 fetchData 实例同时启动,在某个特定时刻,我们可以启动一个新的 fetchData 任务, 尽管之前还有一个或多个 fetchData 尚未结束
如果我们只想得到最新那个请求的响应(例如,始终显示最新版本的数据),我们可以使用 takeLatest 辅助函数
import { takeLatest } from 'redux-saga' function* watchFetchData() { yield* takeLatest('FETCH_REQUESTED', fetchData) }
和takeEvery不同,在任何时刻 takeLatest 只允许执行一个 fetchData 任务,并且这个任务是最后被启动的那个,如果之前已经有一个任务在执行,那之前的这个任务会自动被取消
2、Effect Creators
redux-saga框架提供了很多创建effect的函数,下面我们就来简单的介绍下开发中最常用的几种
take(pattern)
put(action)
call(fn, ...args)
fork(fn, ...args)
select(selector, ...args)
take(pattern)