资讯专栏INFORMATION COLUMN

Redux-saga 初探

yuanxin / 1673人阅读

摘要:背景项目用的是全家桶,之前有同事用改进了一波,一直都没去研究。这次的打算写一个输入框,输入拼音会返回对应的城市列表。

背景

项目用的是react全家桶, 之前有同事用redux-saga 改进了一波, 一直都没去研究。 前几天趁有空,也去学习了下, 写了个简单的demo练练手, 在这里简单分享一下。

这次的demo打算写一个输入框,输入拼音会返回对应的城市列表。并尽可能多的使用redux-saga的特性

起步

首先是使用 create-react-app 创建新的项目,并npm install react-redux redux redux-saga --save

上网随便搜索了一段城市信息的json,保存为city.js

const cities = [{label:"北京Beijing010",name:"北京",pinyin:"Beijing",zip:"010"},
  {label:"重庆Chongqing023",name:"重庆",pinyin:"Chongqing",zip:"023"},
  {label:"上海Shanghai021",name:"上海",pinyin:"Shanghai",zip:"021"},...]

export default cites;

接着是构思state,state有两个值,一个是value代表输入的值,另一个是数组list,代表筛选的结果

reducers.js

// 设置两个action,一个是设置value,一个是设置list

const reducer = (state, action) => {
  switch (action.type) {
    case "INPUT":
      return {...state, value: action.payload}
    case "SET_LIST":
      return {...state, list: action.payload}
  }
  return {...state}
}
export default reducer

APP.js

App为纯函数组件,react-redux的connect方法中传入两个参数,mapStateToProps将state传入App的props,mapActionToProps讲handleChange传入App,当调用handleChange时,会调用INPUT这个action

import React, { Component } from "react";
import "./App.css";
import { connect } from "react-redux"
const App = props =>
  (
    {props.list.map(i =>
  • {i.name}
  • )}
) const mapStateToProps = state => ({ value: state.value, list: state.list }) const mapActionToProps = dispatch => ({ handleChange: v => dispatch({ type: "INPUT", payload: v.target.value }) }) // export default App export default connect(mapStateToProps, mapActionToProps)(App);

接着是我们的主角saga.js

takeEvery可以监听对应的action,如果为*号则监听所有的action,如果action.type匹配,调用对应的回调函数。

put可以主动去触发action,在这里触发了获取的城市结果

import {takeEvery, put, take} from "redux-saga/effects"
import cities from "./city"
function* input() {
  yield takeEvery("INPUT", function* (v) {
    let filterCities = yield getData(v.payload)
    yield put({type: "SET_LIST", payload: filterCities.slice(0, 10)})
  });
}
function getData (v) {
  return new Promise(function (res, rej) {
    setTimeout(() => res(cities.filter(i => i.pinyin.toUpperCase().includes(v.toUpperCase()))), 1000)
  })
}
export default input
input函数也可以使用take来替代takeEvery

function* input() {
   while (true) {
    let v = yield take("INPUT")
    let filterCities = yield getData(v)
    yield put({type: "SET_LIST", payload: filterCities.slice(0, 10)})
  }
}

接下来是最复杂的index.js部分

import React from "react";
import { render } from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
import { Provider } from "react-redux"
import createSagaMiddleware from "redux-saga"
import { createStore, applyMiddleware } from "redux"
import reducers from "./reducers"
import saga from "./sagas"
const sagaMiddleware = createSagaMiddleware()
const store = createStore(reducers, {value: "", list: []}, applyMiddleware(sagaMiddleware))
sagaMiddleware.run(saga)
render(
 
 
,
 document.getElementById("root"));
registerServiceWorker();

到这里,城市拼音输入框就初步完成了

进阶

取消
先加入如果输入数字的话,立刻停止查询并console报错的功能

修改saga.js

首先,导入fork和cancel两个函数,redux-saga的cancel只能取消fork的任务

import {takeEvery, put, take, cancel, fork} from "redux-saga/effects"

// 新加一个check函数,跟之前的input有点类型,如果监测到有数字,会调用CANCEL

function* check  () {
  yield takeEvery("INPUT", function* (v) {
    if (/d+/.test(v.payload)) {
      console.log("x  ")
      yield put({type: "CANCEL"})
    }
  })
}

加入函数main, 首先添加使用fork操作,将input任务保存为i,在碰到cancel的时候,取消该任务,并重新开始新的任务

function* main () {
  yield fork(check)
  let i = yield fork(input)
  while (true) {
    yield take("CANCEL")
    console.log("cancel")
    yield cancel(i)
    i = yield fork(input)
  }
}

最后导出main

export default main

channel
令函数是依次查询,只有之前的查询完成后,才继续查询后面的

引用actionChannel 的effect,修改函数input:

function* input () {
  const inputChan = yield actionChannel("INPUT")
  while (true) {
    const v = yield take(inputChan)
    const filterCities = yield call(getData, v)
    console.log("done")
    yield put({type: "SET_LIST", payload: filterCities.slice(0, 10)})
  }
}

END

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95896.html

相关文章

  • redux-saga框架使用详解及Demo教程

    摘要:通过创建将所有的异步操作逻辑收集在一个地方集中处理,可以用来代替中间件。 redux-saga框架使用详解及Demo教程 前面我们讲解过redux框架和dva框架的基本使用,因为dva框架中effects模块设计到了redux-saga中的知识点,可能有的同学们会用dva框架,但是对redux-saga又不是很熟悉,今天我们就来简单的讲解下saga框架的主要API和如何配合redux框...

    Nosee 评论0 收藏0
  • React生态,dva源码阅读

    摘要:下面会从浅到深,淡淡在阅读源码过程中自己的理解。分拆子页面后,每一个子页面对应一个文件。总结上面就是最早版本的源码,很简洁的使用了等其目的也很简单简化相关生态的繁琐逻辑参考源码地址   dva的思想还是很不错的,大大提升了开发效率,dva集成了Redux以及Redux的中间件Redux-saga,以及React-router等等。得益于Redux的状态管理,以及Redux-saga中...

    bergwhite 评论0 收藏0
  • React生态,dva源码阅读

    摘要:下面会从浅到深,淡淡在阅读源码过程中自己的理解。分拆子页面后,每一个子页面对应一个文件。总结上面就是最早版本的源码,很简洁的使用了等其目的也很简单简化相关生态的繁琐逻辑参考源码地址   dva的思想还是很不错的,大大提升了开发效率,dva集成了Redux以及Redux的中间件Redux-saga,以及React-router等等。得益于Redux的状态管理,以及Redux-saga中...

    txgcwm 评论0 收藏0
  • React生态,dva源码阅读

    摘要:下面会从浅到深,淡淡在阅读源码过程中自己的理解。分拆子页面后,每一个子页面对应一个文件。总结上面就是最早版本的源码,很简洁的使用了等其目的也很简单简化相关生态的繁琐逻辑参考源码地址   dva的思想还是很不错的,大大提升了开发效率,dva集成了Redux以及Redux的中间件Redux-saga,以及React-router等等。得益于Redux的状态管理,以及Redux-saga中...

    harryhappy 评论0 收藏0

发表评论

0条评论

yuanxin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<