React redux saga 基本使用流程

React redux saga 基本使用流程

redux-saga 是一个用于管理redux应用异步操作代替 redux-thunk 的中间件

集中处理 redux 副作用问题。reducer负责处理action的更新,saga负责协调那些复杂或者异步的操作

本文主要描述联合使用redux 和saga模式的方法,以及单独使用react-redux 和redux-saga的方法

用自己的话捋一遍二者的流程和融合使用方式

1.首先我们先捋一遍react-redux的执行流程

在需要使用redux的组件中,我们需要使用connect对组件进行连接,那么具体连接什么呢?

这里需要提到两个重要的对象:mapStateToPropsmapDispatchToProps,见名知意,将state和action转为props传入被包裹的组件,这样就可以从props接收到了,

注意,这里的state是redux管理的,通常会由各自的reducer管理,也就是state.counterReducer.count这样子,同时这个state的初始状态也是在reducer中定义的。

2.那么,当点击事件触发,就会执行increment和decrement,它们是两个action

这个reducer会被发到reducer中进行挨个匹配,要注意重名的情况哟,将初始state作为参数传入reducer函数,action就是上面发来的,这里使用action.type判断是哪个action,使用payload获取传来的数据,注意在reducer处理action后,我们需要返回的是经过操作更新后的新状态即可

3.然后我们来看一下redux-saga又怎么用呢,当然首先要记得在store中添加saga中间件,我们还是从一个请求例子开始

这里发起了一个action,那么谁会来处理呢?

4.Redux-Saga Workers配合根 Saga会进行处理,在worker中监听action,并指定对应的处理函数,使用yield和put,take,call等方法实现工作器函数的逻辑,那么worker监听action由rootSaga来进行管理,使用all方面添加需要监听的saga,这个rootSage需要在store配置中间件时_// 运行根 Saga_ sagaMiddleware.run(rootSaga);

5.那么工作器函数的逻辑也只是put了一个action而已,目的只是为了组合逻辑,最后还是要reducer来处理的

jsx 复制代码
import { connect } from 'react-redux';
import { increment, decrement } from './actions';

const Counter = (props) => {
  { count, increment, decrement } = props
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

const mapStateToProps = (state) => ({
  count: state.counterReducer.count,
});

const mapDispatchToProps = {
  increment,
  decrement,
};

export default connect(mapStateToProps, mapDispatchToProps)(Counter);
jsx 复制代码
// actions.js
export const increment = () => ({
  type: 'INCREMENT',
});

export const decrement = () => ({
  type: 'DECREMENT',
});
export const change = (item) => {
  return {
    type:"change-city",
    payload:item
  }
}
jsx 复制代码
// reducers.js
const initialState = {
  count: 0,
};

const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return {
        ...state,
        count: state.count + 1,
      };
    case 'DECREMENT':
      return {
        ...state,
        count: state.count - 1,
      };
    default:
      return state;
  }
};

export default counterReducer;
jsx 复制代码
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

const DataComponent = () => {
  const dispatch = useDispatch();
  const data = useSelector(state => state.data.data);  
  const isLoading = useSelector(state => state.data.isLoading);

  useEffect(() => {
    // 在组件渲染时触发异步请求
    dispatch({ type: 'FETCH_DATA' });
  }, [dispatch]);

  // 渲染数据
  return (
    <div>内容</div>
  );
};

export default DataComponent;
jsx 复制代码
// src/sagas/data.js  worker
import { call, put, takeEvery } from 'redux-saga/effects';
import api from '../api';

// 定义异步请求函数
const fetchDataFromApi = async () => {
  // 这里可以使用真实的异步请求
  const response = await api.getData();
  return response;
};

// 定义工作器函数,处理异步请求流程
function* fetchDataSaga() {
  try {
    yield put({ type: 'FETCH_DATA_REQUEST' });
    const data = yield call(fetchDataFromApi);
    yield put({ type: 'FETCH_DATA_SUCCESS', payload: data });
  } catch (error) {
    yield put({ type: 'FETCH_DATA_FAILURE', payload: error.message });
  }
}

// 监听触发异步请求的动作,并调用相应的工作器函数
export function* watchFetchData() {
  yield takeEvery('FETCH_DATA', fetchDataSaga);
}
jsx 复制代码
// src/sagas/index.js rootSaga
import { all } from 'redux-saga/effects';
import { watchFetchData } from './saga/data';

// 在这里引入其他需要监听的 Saga 文件

// 根 Saga,将多个 Saga 组合在一起
export default function* rootSaga() {
  yield all([watchFetchData()]);
  // 在这里添加其他需要监听的 Saga
}
jsx 复制代码
// src/reducers/data.js
// 定义初始状态
const initialState = {
  isLoading: false,
  data: null,
  error: null,
};

// 定义对应的 Reducer
export const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'FETCH_DATA_REQUEST':
      return {
        ...state,
        isLoading: true,
        error: null,
      };
    case 'FETCH_DATA_SUCCESS':
      return {
        ...state,
        isLoading: false,
        data: action.payload,
      };
    case 'FETCH_DATA_FAILURE':
      return {
        ...state,
        isLoading: false,
        error: action.payload,
      };
    default:
      return state;
  }
};

Redux-Saga 全流程示例

Redux-Saga 是一个用于管理应用程序副作用(例如异步请求和数据获取)的库。下面是一个简单的 Redux-Saga 全流程示例:

  1. 安装 Redux 和 Redux-Saga:
jsx 复制代码
npm install redux redux-saga
  1. 创建 Redux Store,包括创建 Redux-Saga 中间件:
jsx 复制代码
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './reducers';
import rootSaga from './sagas';

// 创建 Saga 中间件
const sagaMiddleware = createSagaMiddleware();

// 创建 Redux Store,并应用 Saga 中间件
const store = createStore(
  rootReducer,
  applyMiddleware(sagaMiddleware)
);

// 运行根 Saga
sagaMiddleware.run(rootSaga);

export default store;
  1. 创建 Redux Reducers:
jsx 复制代码
// src/reducers/index.js

import { combineReducers } from 'redux';
import { reducer as dataReducer } from './data';

const rootReducer = combineReducers({
  // 将各个子 Reducer 组合在一起
  data: dataReducer,
});

export default rootReducer;
  1. 创建 Redux-Saga Schemas:
jsx 复制代码
// src/reducers/data.js

// 定义初始状态
const initialState = {
  isLoading: false,
  data: null,
  error: null,
};

// 定义对应的 Reducer
export const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'FETCH_DATA_REQUEST':
      return {
        ...state,
        isLoading: true,
        error: null,
      };
    case 'FETCH_DATA_SUCCESS':
      return {
        ...state,
        isLoading: false,
        data: action.payload,
      };
    case 'FETCH_DATA_FAILURE':
      return {
        ...state,
        isLoading: false,
        error: action.payload,
      };
    default:
      return state;
  }
};
  1. 创建 Redux-Saga Workers:
jsx 复制代码
// src/sagas/data.js

import { call, put, takeEvery } from 'redux-saga/effects';
import api from '../api';

// 定义异步请求函数
const fetchDataFromApi = async () => {
  // 这里可以使用真实的异步请求
  const response = await api.getData();
  return response;
};

// 定义工作器函数,处理异步请求流程
function* fetchDataSaga() {
  try {
    yield put({ type: 'FETCH_DATA_REQUEST' });
    const data = yield call(fetchDataFromApi);
    yield put({ type: 'FETCH_DATA_SUCCESS', payload: data });
  } catch (error) {
    yield put({ type: 'FETCH_DATA_FAILURE', payload: error.message });
  }
}

// 监听触发异步请求的动作,并调用相应的工作器函数
export function* watchFetchData() {
  yield takeEvery('FETCH_DATA', fetchDataSaga);
}
  1. 创建根 Saga:
jsx 复制代码
// src/sagas/index.js

import { all } from 'redux-saga/effects';
import { watchFetchData } from './data';

// 在这里引入其他需要监听的 Saga 文件

// 根 Saga,将多个 Saga 组合在一起
export default function* rootSaga() {
  yield all([watchFetchData()]);
  // 在这里添加其他需要监听的 Saga
}
  1. 使用 Redux-Saga 发起异步请求:
jsx 复制代码
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

const DataComponent = () => {
  const dispatch = useDispatch();
  const data = useSelector(state => state.data.data);
  const isLoading = useSelector(state => state.data.isLoading);

  useEffect(() => {
    // 在组件渲染时触发异步请求
    dispatch({ type: 'FETCH_DATA' });
  }, [dispatch]);

  // 渲染数据
  return (
    <div>
      {isLoading ? (
      <p>Loading...</p>
    ) : data ? (
      <p>{data}</p>
    ) : (
      <p>No data available</p>
    )}
    </div>
  );
};

export default DataComponent;

这是一个基本的 Redux-Saga 全流程示例,包括创建 Redux Store、定义 Reducers、编写 Saga 和工作器函数,以及在组件中使用 Redux-Saga 发起异步请求。

下面是 Redux-Saga 的工作流程:

  1. 创建 Saga 中间件:在创建 Redux Store 之前,先创建 Redux-Saga 中间件。使用 createSagaMiddleware 函数来创建中间件实例。
  2. 创建根 Saga:编写根 Saga 函数,用于管理各个子 Saga。根 Saga 是一个 Generator 函数,通过使用 yield all([...]) 将多个子 Saga 组合在一起。
  3. 编写 Worker 函数:在单独的 Saga 文件中,编写用于处理具体异步任务的 Worker 函数。Worker 函数是一个 Generator 函数,并且会被根 Saga 监听特定的 action。
  4. 监听并触发 Action:在根 Saga 中使用 takeEverytakeLatest 等 effect 函数来监听指定的 action,一旦该 action 被触发,对应的 Worker 函数将被执行。
  5. 处理异步逻辑:在 Worker 函数中,使用 Redux-Saga 提供的各种 effect 函数来处理异步逻辑。例如,使用 call 来调用异步函数,使用 put 来派发新的 action。
  6. 更新 Redux Store:在 Worker 函数中,使用 put effect 来派发新的 action,通知 Redux Store 更新状态。这些新的 action 可以被其他 Reducer 处理,从而改变应用程序的状态。
  7. 监听并取消异步任务:Redux-Saga 还提供了 takecancel 等 effect 函数,用于监听特定的 action 并取消正在进行的异步任务。
    通过以上流程,Redux-Saga 能够管理应用程序中的异步逻辑,并与 Redux Store 进行交互,以保持状态更新和一致性。

React-Redux 全流程示例

下面是一个简单的 React-Redux 全流程示例,包括创建 Redux Store、定义 Actions、编写 Reducers、使用 Connect 连接组件以及在组件中触发 Actions 和访问状态:

  1. 创建 Redux Store:
jsx 复制代码
import { createStore } from 'redux';
import rootReducer from './reducers';

const store = createStore(rootReducer);
  1. 定义 Actions:
jsx 复制代码
// actions.js
export const increment = () => ({
  type: 'INCREMENT',
});

export const decrement = () => ({
  type: 'DECREMENT',
});
  1. 编写 Reducers:
jsx 复制代码
// reducers.js
const initialState = {
  count: 0,
};

const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return {
        ...state,
        count: state.count + 1,
      };
    case 'DECREMENT':
      return {
        ...state,
        count: state.count - 1,
      };
    default:
      return state;
  }
};

export default counterReducer;
  1. 使用 Connect 连接组件:
jsx 复制代码
import { connect } from 'react-redux';
import { increment, decrement } from './actions';

const Counter = ({ count, increment, decrement }) => {
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

const mapStateToProps = (state) => ({
  count: state.count,
});

const mapDispatchToProps = {
  increment,
  decrement,
};

export default connect(mapStateToProps, mapDispatchToProps)(Counter);
  1. 在组件中触发 Actions 和访问状态:
jsx 复制代码
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import Counter from './Counter';

ReactDOM.render(
  <Provider store={store}>
    <Counter />
  </Provider>,
  document.getElementById('root')
);

在上面的例子中,创建了一个 Redux Store,并定义了两个简单的 Actions(increment 和 decrement)。然后编写了 Reducer 来处理这些 Actions 并更新应用程序的状态。 接下来使用 Connect 函数连接 Counter 组件与 Redux Store,并通过 mapStateToProps 将需要的状态映射到组件的 props 中,通过 mapDispatchToProps 将 Actions 映射到组件的 props 中。最后,在根组件中使用 Provider 包裹 Counter 组件,并传入 Redux Store。

这样,在 Counter 组件中就可以通过 props 访问 count 状态,并通过调用 increment 和 decrement 方法来触发对应的 Actions,从而实现状态的更新和响应。

  1. 创建 Redux Store:首先,需要创建一个 Redux Store 来存储应用程序的状态。通过 createStore 函数可以创建一个全局唯一的状态树,并将 Reducers 和中间件传递给 createStore。
  2. 定义 Actions:Actions 是描述状态变化的纯 JavaScript 对象。每个 Action 都必须包含一个 type 字段来表示该动作的类型,并且可以包含其他任意字段用于传递数据。可以通过编写 Action Creator 函数来创建 Action,这些函数返回一个 Action 对象。
  3. 编写 Reducers:Reducers 是纯函数,用于根据 Action 的类型更新状态。Reducer 接收当前的状态和要处理的 Action,并根据 Action 类型进行相应的状态更新操作,然后返回一个新的状态对象。注意,Reducer 必须是纯函数,即给定相同的输入,始终产生相同的输出,不会对原有的状态进行修改。
  4. 使用 Connect 连接组件:为了在 React 组件中访问 Redux Store 中的状态以及触发 Actions,需要使用 Redux 的 connect 函数将组件连接到 Redux Store。connect 函数接收两个参数:mapStateToPropsmapDispatchToPropsmapStateToProps 函数将 Redux Store 中的状态映射到组件的 props,而 mapDispatchToProps 函数将 Action Creators 映射到组件的 props。
  5. 在组件中触发 Actions 和访问状态:通过连接到 Redux Store 的组件可以访问映射后的状态和 Actions。组件可以使用 props 中的状态来展示数据,并通过调用 props 中的 Action Creators 来触发对应的动作,从而更新 Redux Store 中的状态。
  6. Redux Store 的更新和通知:当组件触发了一个 Action 后,Redux Store 会根据 Reducers 的逻辑进行状态更新。Reducers 计算出新的状态并返回给 Redux Store。Redux Store 将新的状态更新到自己身上,并通知已经注册的监听器(例如 React 组件),以便它们可以获取最新的状态并重新渲染。
相关推荐
GISer_Jing7 分钟前
Vue3状态管理——Pinia
前端·javascript·vue.js
好开心3322 分钟前
axios的使用
开发语言·前端·javascript·前端框架·html
Domain-zhuo31 分钟前
Git常用命令
前端·git·gitee·github·gitea·gitcode
菜根Sec1 小时前
XSS跨站脚本攻击漏洞练习
前端·xss
m0_748257181 小时前
Spring Boot FileUpLoad and Interceptor(文件上传和拦截器,Web入门知识)
前端·spring boot·后端
桃园码工1 小时前
15_HTML5 表单属性 --[HTML5 API 学习之旅]
前端·html5·表单属性
百万蹄蹄向前冲2 小时前
2024不一样的VUE3期末考查
前端·javascript·程序员
Anlici2 小时前
three.js建立3D模型展示地球+高亮
前端·数据可视化·canvas
轻口味2 小时前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami3 小时前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json