在上一篇 redux在react-native上使用(一)--加入redux 已成功把redux
添加到項(xiàng)目, 現(xiàn)在再把redux-saga
添加進(jìn)來.
這篇 redux在react-native上使用(三)--加入redux-thunk 是使用redux-thunk
, 可以跟這篇做個(gè)對(duì)比看下redux-thunk
和redux-saga
使用上的區(qū)別.
這一次做個(gè)跑秒器. 點(diǎn)擊開始
按鈕就開始跑秒,點(diǎn)擊停止
按鈕停止跑秒, 點(diǎn)擊重置
按鈕時(shí)間就清零. 跑秒狀態(tài)下數(shù)字為藍(lán)色,停止?fàn)顟B(tài)下為黑色.
先在package.json
里添加redux-saga
庫, 并在目錄下npm install
:
"dependencies": {
...
"redux-saga": "^0.11.0"
},
把action
名字改得更有意義點(diǎn), actionsTypes.js
:
export const START = 'START';
export const STOP = 'STOP';
export const RESET = 'RESET';
export const RUN_TIMER = 'RUN_TIMER';
actions.js
跟著改:
import { START, STOP, RESET, RUN_TIMER } from './actionsTypes';
const start = () => ({ type: START });
const stop = () => ({ type: STOP });
const reset = () => ({ type: RESET });
const runTime = () => ({ type: RUN_TIMER });
export {
start,
stop,
reset,
runTime
}
reducers.js
在action
改變后也需要調(diào)整:
import { combineReducers } from 'redux';
import { START, STOP, RESET, RUN_TIMER } from './actionsTypes';
// 原始默認(rèn)state
const defaultState = {
seconds: 0,
runStatus: false
}
function timer(state = defaultState, action) {
switch (action.type) {
case START:
return { ...state, runStatus: true };
case STOP:
return { ...state, runStatus: false };
case RESET:
return { ...state, seconds: 0 };
case RUN_TIMER:
return { ...state, seconds: state.seconds + 1 };
default:
return state;
}
}
export default combineReducers({
timer
});
添加一個(gè)sagas.js
文件, 處理項(xiàng)目的業(yè)務(wù)邏輯:
import { takeEvery, delay, END } from 'redux-saga';
import { put, call, take, fork, cancel, cancelled } from 'redux-saga/effects';
import { START, STOP, RESET, RUN_TIMER } from './actionsTypes';
import { stop, runTime } from './actions';
function* watchStart() {
// 一般用while循環(huán)替代 takeEvery
while (true) {
// take: 等待 dispatch 匹配某個(gè) action
yield take(START);
// 通常fork 和 cancel配合使用剑逃,實(shí)現(xiàn)非阻塞任務(wù),take是阻塞狀態(tài),也就是實(shí)現(xiàn)執(zhí)行take時(shí)候劲腿,無法向下繼續(xù)執(zhí)行迁杨,fork是非阻塞的糠排,同樣可以使用cancel取消一個(gè)fork 任務(wù)
var runTimeTask = yield fork(timer);
yield take(STOP);
// cancel: 取消一個(gè)fork任務(wù)
yield cancel(runTimeTask);
}
}
function* watchReset() {
while (true) {
yield take(RESET)
yield put(stop());
}
}
function* timer() {
try {
while(true) {
// call: 有阻塞地調(diào)用 saga 或者返回 promise 的函數(shù)伶选,只在觸發(fā)某個(gè)動(dòng)作
yield call(delay, 1000);
// put: 觸發(fā)某個(gè)action词渤, 作用和dispatch相同
yield put(runTime());
}
} finally {
if (yield cancelled()) {
console.log('取消了runTimeTask任務(wù)');
}
}
}
export default function* rootSaga() {
yield fork(watchStart);
yield fork(watchReset)
}
把saga
作為中間件添加進(jìn)store
, store.js
如下:
import { createStore, applyMiddleware, compose } from 'redux';
import createSagaMiddleware, { END } from 'redux-saga';
import createLogger from 'redux-logger';
import rootReducer from './reducers';
import sagas from './sagas';
const configureStore = preloadedState => {
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
rootReducer,
preloadedState,
compose (
applyMiddleware(sagaMiddleware, createLogger())
)
)
sagaMiddleware.run(sagas);
store.close = () => store.dispatch(END);
return store;
}
const store = configureStore();
export default store;
home.js
修改下:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity
} from 'react-native';
import { connect } from 'react-redux';
import { reset, start, stop } from './actions';
class Home extends Component {
_onPressReset() {
this.props.dispatch(reset());
}
_onPressInc() {
this.props.dispatch(start());
}
_onPressDec() {
this.props.dispatch(stop());
}
render() {
return (
<View style={styles.container}>
<Text style={styles.counter}>{this.props.timer.seconds}</Text>
<TouchableOpacity style={styles.reset} onPress={()=>this._onPressReset()}>
<Text>重置</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.start} onPress={()=>this._onPressInc()}>
<Text>開始</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.stop} onPress={()=>this._onPressDec()}>
<Text>停止</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column'
},
counter: {
fontSize: 70,
marginBottom: 70,
color: '#FF8500'
},
reset: {
margin: 10,
backgroundColor: 'yellow'
},
start: {
margin: 10,
backgroundColor: 'yellow'
},
stop: {
margin: 10,
backgroundColor: 'yellow'
}
});
const mapStateToProps = state => ({
timer: state.timer
})
export default connect(mapStateToProps)(Home);
OK, 大功告成, commond+R
運(yùn)行.