目录

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 组件),以便它们可以获取最新的状态并重新渲染。
本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
腾讯TNTWeb前端团队2 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰5 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪5 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪5 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy6 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom6 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom7 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom7 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom7 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom7 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试