Redux-saga初探侦

5014 ワード

背景
プロジェクトはreact家族の桶を使っています.以前は同僚がredux-sagaで改善しました.ずっと研究に行きませんでした.先日暇があったら、勉強に行きました.簡単なデモトレーナーを書いて、ここで簡単にシェアしてみました.
今回のデモは入力枠を書くつもりです.ピンインを入力すれば対応する都市リストに戻ります.そしてできるだけ多くの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は入力の値を表します.もう一つは配列リストです.フィルタの結果を表します.
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
P.js
Appは純関数コンポーネントであり、react-reduxのconnect方法では二つのパラメータが導入されています.mapStation ToPropsはstateをAppのpropsに導入し、MapAct ToPropsはhandleChangeをアプリに導入し、handle Changeを呼び出したときに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();
ここで、都市ピンイン入力ボックスは一応完成しました.
階段を進める
まず数字を入力すると、すぐに検索を停止して、soneエラーを知らせる機能を追加します.
saga.jsを修正します
まず、forkとcancelの2つの関数を導入して、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)
  }
}
最後にメールをエクスポートします
export default main
chanel命令関数は順を追って調べますが、前のクエリが完了してから、後の確認を続けます.
actionChanelの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