yarn add redux-saga
mysaga.js 定義saga文件
import {call, put, takeEvery} from 'redux-saga/effects' // 模擬登陸接口 const UserService = { login(name) { return new Promise((resolve, reject) => { console.log('login', name) setTimeout(() => { if(name === '小明') { console.log('suc') resolve({name: '小明'}) } else { reject({name: '用戶名或密碼錯誤'}) } }, 1000) }) } } function* loginHandle(action) { // generator將異步操作改為同步 console.log('loginHandle', action) try{ const res = yield call(UserService.login, action.name) //call執行UserService.login,並且將action.name當參數傳遞過去 console.log('res', res) yield put({type: 'requestSuccess', res}) // put和dispatch類似,執行reducer } catch (error) { console.log('error', error) yield put({type: 'requestFailure', error}) } } function* mySaga() { yield takeEvery('login', loginHandle) // 類似於將函數重命名,調用login則會執行loginHandle,並且將login得參數傳遞過去 } export default mySaga
store.js 存儲公共狀態文件
import {createStore, combineReducers, applyMiddleware} from 'redux' import thunk from 'redux-thunk' // 此處沒有用到 import createSagaMiddleware from 'redux-saga' // 引入createSagaMiddleware import mySaga from '../mySage' const initalLogin = { isLogin: false, // 是否登陸 loading: false, // 登陸狀態 name: '', error: '' } const sagaMiddleware = createSagaMiddleware() // 創建中間件 function loginReducer(state = {...initalLogin}, action) { console.log('loginReducer', action) switch (action.type) { case 'requestLogin': return {...state, loading: true} case 'requestSuccess': return {...state,isLogin: true, loading: false} case 'requestFailure': return {...state,isLogin: false, loading: false, error: action.error.name} default: return state } } const store = createStore( combineReducers({user: loginReducer}), // applyMiddleware(thunk) applyMiddleware(sagaMiddleware) // 將中間件放入applyMiddleware ) sagaMiddleware.run(mySaga) // 此處必須執行run() export default store
loginPage.js 具體調用頁面
import React, {Component} from 'react'; import {Redirect} from 'react-router-dom' import {connect} from "react-redux"; class LoginPage extends Component { constructor(props) { super(props); this.state = { name: '' } } changeName = (event) => { this.setState({ name: event.target.value }) } render() { const {isLogin,loading, location, loginSuccess, login, error} = this.props console.log('loginPage', this.props) const {name} = this.state if(isLogin) { const {redirect = '/'} = location.state || {} return <Redirect to={redirect} /> } return ( <div> <h1>loginPage</h1> <input type="text" value={name} onChange={this.changeName}/> <button onClick={() => login(name)}>{loading ? '登錄中': '登錄'}</button> { error && (<p>{error}</p>) // 有錯誤信息則顯示 } </div> ); } } const mapStateToprops = state => { return { isLogin: state.user.isLogin, loading: state.user.loading, error: state.user.error } } const mapDispatchToProps = { // 方法映射到props上 // loginSuccess: () => { // return {type: 'requestSuccess'} // }, // loginSuccess: () => dispatch => { // dispatch({type: 'requestLogin'}) // setTimeout(() => { // dispatch({type: 'requestSuccess'}) // }, 2000) // }, login : (name) => { // 這里會接收到調用login方法傳得得參數 return ({type: 'login', name}) } } export default connect(mapStateToprops, mapDispatchToProps)(LoginPage)
以下是數據傳遞方式