从0开始,使用redux-saga写一个案例(1)

165 阅读4分钟

首先安装react 脚手架

可以看我的作品

react 脚手架的安装和使用(1) - 掘金 (juejin.cn)

然后删除不必要的文件留下入口文件index.JS和 app.jsx

安装我们需要的依赖

npm install redux react-redux
//安装radux

npm install --save redux-devtools-extension //安装调试工具

当然首先呢我们先用react-redux 写一个 计数器的案例。

首先我们创建一个reducer 函数

当然我们开发肯定是写多个reducer 函数 所以创建一个文件夹使用combineReducers来合并reducer

1.首先创建reducer函数

//ADD,SUB引用的是我写的常量
export const counter =(state={count:0},action)=>{
    console.log("调用了counter");
    switch (action.type){
        case ADD:
            return{
                count:state.count+1
            }
            case SUB:
                return{
                    count:state.count-1
                }
                default :
                return state
    }
}

然后写合并reducer

//首先我们引用redux 的combinReducers 来合并reducr函数

import { combineReducers } from "redux";
//引用reducer函数
import { counter } from "./counter";

export const rootReducer=combineReducers({
    counter
    //简写  counter:counter
})

2.然后在入口文件引入模块并且 创建全局store

import React from 'react';
import ReactDOM from 'react-dom/client';
import reportWebVitals from './reportWebVitals';
//composeWithDevTools是监控中间件的
import { composeWithDevTools } from 'redux-devtools-extension';
import { applyMiddleware, legacy_createStore } from 'redux';
import App from './app';
import { rootReducer } from './counter';
import { Provider } from 'react-redux';

//使用legacy_createStore 创建全局store 并把reducer添加进去
let store =legacy_createStore(rootReducer,composeWithDevTools(applyMiddleware())) 


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
 <Provider store={store}>
   <App />
 </Provider>
   //通过<Provider store={store}></Provider>将store向后代组件传递

);

3.然后写action (action 是用来修改store数据的)


export  const add=()=>{
    return {
        type:ADD
    }
}
export  const sub=()=>{
    return {
        type:SUB
    }
}

4.最后我们写组件APP.jsx

import { connect } from "react-redux";
import { add,sub } from "./action";
const App =(props)=>{
    let {add,sub,counter}=props
    return(
        <>
        <h3>App组件</h3>
        <p>{counter.count}</p>
        <button onClick={()=>add()}>+</button>
        <button onClick={()=>sub()}> -</button>
        </>
    )
}
const mapStateToProps=(state,ownProps)=>{
    return{
        counter:state.counter
    }
}
export default  connect(mapStateToProps,{add,sub})(App) ;

//connect() 
//<1>.调用mapStateToProps函数,将函数返回值和this.propsprops进行合并
//这个函数允许我们将 store 中的数据作为 props 绑定到组件上。
//Object.assign(this.props/props, mapStateToProps函数调用的返回值对象);

//<2>将sotre.dispatch函数添加到组件的this.props/props上

这里我们重点解释一下mapStateToProps

mapStateToProps(state, ownProps) : stateProps

这个函数的第一个参数就是 Redux 的 store,我们从中摘取了 count 属性。你不必将 state 中的数据原封不动地传入组件,可以根据 state 中的数据,动态地输出组件需要的(最小)属性。

(2)函数的第二个参数 ownProps,是组件自己的 props。有的时候,ownProps 也会对其产生影响。

当 state 变化,或者 ownProps 变化的时候,mapStateToProps 都会被调用,计算出一个新的 stateProps,(在与 ownProps merge 后)更新给组件。

最后的效果是一个计数器

1675262553238.png

复习完react-redux 后我们开始正式的讲redux-saga

首先我们需要引用createSagaMiddleware() 创建中间件

const sagaMiddleware =createSagaMiddleware();

然后注册中间件 let store=legacy_createStore(rootReducer,composeWithDevTools(applyMiddleware(sagaMiddleware)) )

我们创建一个saga文件(也就是generator函数)


export function *hello(){
    yield  console.log("tom");
    yield console.log("jarry");
}

最后使用saga 的run方法 运行

sagaMiddleware.run(hello) //递归遍历generator函数 每个yield的状态

结果就是控制台打印了 tom jarry

saga 的API

1. takeEvery

(1)初始化阶段:注册异步action和工作saga之间的关系

(2)更新阶段:先转发action给reducer函数(刷loading),之后调用工作saga实现业务 (刷数据或错误)(也就是一发送异步action 第一个参数 就调用第二个参数工作saga)

2.put 就相当于 dispatch:功能转发action

3.delay 模拟网络延迟—模拟异步

4. takeLatest 功能类似于takeEvery ,用来阻止重复提交—去抖

5. call 调用异步函数---解决地狱回调—特别注意,加不加call都阻塞执行

   call(异步函数,异步的实参);调用异步的时候也是阻塞执行 比如(setTimeout,2000)

6.      fork 调用异步函数---非阻塞执行—非地狱回调—同时发送多个异步请求

7.      all 同时执行多个异步函数

了解好了之后呢我们补充个小案例

异步+数字

首先添加变量

export const ADDASYNC="ADDASYNC"

然后添加action

export const addAsync=()=>{ return { type:ADDASYNC } }

重新写一个reducer 并且合并

    switch (action.type){
        default :
        return state
    }
}

最后写saga文件


import { ADD , ADDASYNC } from "../constants";
//创建work saga
function * gAddAsync(){
    yield delay(2000);
    yield put({type:ADD})


}

export  function * watchgAddAsync (){
    yield console.log("watchgAddAsync被调用");
    yield takeEvery(ADDASYNC,gAddAsync)
     //takeEcery注册了异步action ADDASYNC和 工作saga gaddasync的关系  发送ADDASYNC就调用 gAddAsync

}

//**redux-saga中一个业务需要两种saga:

**     第一种: workSaga:  fulfilled/reject**

**     第二种:watchSsaga  pending—刷loading**

****

然后写到组件上边去

<button onClick={()=>addAsync()}> async</button>

实现延迟两秒 异步加数字

1675268355479.png

步骤如下:

1675268519930.png

1675268590748.png

然后我们写一个异步获取数据的案例

因为你run()方法只能跑一个函数,所以这里我们利用all方法合并saga

首先我们再写一个saga函数

   let res= yield  call(axios.get,"https://jsonplaceholder.typicode.com/users")
   console.log("res",res);
   //随机获取10个数据
}
export function *watchgFetchUser(){
    yield takeEvery(FETCH_USER_SUCCESS,gFetchUser)
}
//然后进行合并
export function * rootSaga(){
    yield  all([
        watchgAddAsync(),
        watchgFetchUser()
    ])
}

再写一个action添加方法

export  const fetch_user  =()=>{
    return {
        type:FETCH_USER_SUCCESS
    }
}

最后我们添加到组件中

<button onClick={()=>fetch_user()}>fetch_user</button>

效果如图

1675300890433.png