You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中Redux-Saga配置指南:文件夹结构与代码拆分示例

我完全懂你这种多层传递props的烦躁!当初我刚接触React Native的时候,也被这种来回传token的操作搞得头大,选Redux-Saga绝对是个明智的选择——它把异步逻辑和UI逻辑拆得清清楚楚,维护起来特别省心。下面我就一步步给你讲怎么配置,还有针对Product和Firmware页面的代码拆分,结构跟你熟悉的Redux-Thunk差不多,很快就能上手~


第一步:先搭好文件夹结构

咱们按照模块拆分,每个页面(Product/Firmware)都有自己独立的actionTypes、actions、saga和reducer,结构清晰还不容易乱:

src/
├── store/
│   ├── index.js          # 核心store配置,整合saga和reducer
│   ├── rootSaga.js       # 合并所有子模块的saga
│   ├── rootReducer.js    # 合并所有子模块的reducer
│   ├── product/          # Product专属模块
│   │   ├── actionTypes.js
│   │   ├── actions.js
│   │   ├── saga.js
│   │   └── reducer.js
│   └── firmware/         # Firmware专属模块
│       ├── actionTypes.js
│       ├── actions.js
│       ├── saga.js
│       └── reducer.js
└── components/           # 页面组件
    ├── ProductScreen.js
    └── FirmwareScreen.js

第二步:逐个模块写代码

先从Product模块开始

1. 定义action类型(actionTypes.js)
// src/store/product/actionTypes.js
export const FETCH_PRODUCTS_REQUEST = 'FETCH_PRODUCTS_REQUEST';
export const FETCH_PRODUCTS_SUCCESS = 'FETCH_PRODUCTS_SUCCESS';
export const FETCH_PRODUCTS_FAILURE = 'FETCH_PRODUCTS_FAILURE';
2. 写action创建函数(actions.js)
// src/store/product/actions.js
import {
  FETCH_PRODUCTS_REQUEST,
  FETCH_PRODUCTS_SUCCESS,
  FETCH_PRODUCTS_FAILURE,
} from './actionTypes';

// 请求开始的action
export const fetchProductsRequest = () => ({
  type: FETCH_PRODUCTS_REQUEST,
});

// 请求成功的action
export const fetchProductsSuccess = (products) => ({
  type: FETCH_PRODUCTS_SUCCESS,
  payload: products,
});

// 请求失败的action
export const fetchProductsFailure = (error) => ({
  type: FETCH_PRODUCTS_FAILURE,
  payload: error,
});
3. 写saga处理异步逻辑(saga.js)

这里用axios发请求,记得带上存在AsyncStorage里的JWT Token:

// src/store/product/saga.js
import { call, put, takeLatest } from 'redux-saga/effects';
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
  FETCH_PRODUCTS_REQUEST,
  fetchProductsSuccess,
  fetchProductsFailure,
} from './actionTypes';

// 实际的API请求函数
const fetchProductsApi = async () => {
  const token = await AsyncStorage.getItem('jwtToken');
  const response = await axios.get('https://你的接口地址/products', {
    headers: { Authorization: `Bearer ${token}` },
  });
  return response.data;
};

// Saga工作函数:处理请求逻辑
function* fetchProducts() {
  try {
    const products = yield call(fetchProductsApi); // 调用API
    yield put(fetchProductsSuccess(products)); // 派发成功action
  } catch (error) {
    yield put(fetchProductsFailure(error.message)); // 派发失败action
  }
}

// Saga监听函数:监听请求action,避免重复请求
export function* watchFetchProducts() {
  yield takeLatest(FETCH_PRODUCTS_REQUEST, fetchProducts);
}
4. 写reducer更新状态(reducer.js)
// src/store/product/reducer.js
import {
  FETCH_PRODUCTS_REQUEST,
  FETCH_PRODUCTS_SUCCESS,
  FETCH_PRODUCTS_FAILURE,
} from './actionTypes';

const initialState = {
  loading: false,
  products: [],
  error: '',
};

const productReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_PRODUCTS_REQUEST:
      return { ...state, loading: true };
    case FETCH_PRODUCTS_SUCCESS:
      return { loading: false, products: action.payload, error: '' };
    case FETCH_PRODUCTS_FAILURE:
      return { loading: false, products: [], error: action.payload };
    default:
      return state;
  }
};

export default productReducer;

再写Firmware模块(和Product结构完全一致,替换业务内容即可)

1. actionTypes.js
// src/store/firmware/actionTypes.js
export const FETCH_FIRMWARES_REQUEST = 'FETCH_FIRMWARES_REQUEST';
export const FETCH_FIRMWARES_SUCCESS = 'FETCH_FIRMWARES_SUCCESS';
export const FETCH_FIRMWARES_FAILURE = 'FETCH_FIRMWARES_FAILURE';
2. actions.js
// src/store/firmware/actions.js
import {
  FETCH_FIRMWARES_REQUEST,
  FETCH_FIRMWARES_SUCCESS,
  FETCH_FIRMWARES_FAILURE,
} from './actionTypes';

export const fetchFirmwaresRequest = () => ({
  type: FETCH_FIRMWARES_REQUEST,
});

export const fetchFirmwaresSuccess = (firmwares) => ({
  type: FETCH_FIRMWARES_SUCCESS,
  payload: firmwares,
});

export const fetchFirmwaresFailure = (error) => ({
  type: FETCH_FIRMWARES_FAILURE,
  payload: error,
});
3. saga.js
// src/store/firmware/saga.js
import { call, put, takeLatest } from 'redux-saga/effects';
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
  FETCH_FIRMWARES_REQUEST,
  fetchFirmwaresSuccess,
  fetchFirmwaresFailure,
} from './actionTypes';

const fetchFirmwaresApi = async () => {
  const token = await AsyncStorage.getItem('jwtToken');
  const response = await axios.get('https://你的接口地址/firmwares', {
    headers: { Authorization: `Bearer ${token}` },
  });
  return response.data;
};

function* fetchFirmwares() {
  try {
    const firmwares = yield call(fetchFirmwaresApi);
    yield put(fetchFirmwaresSuccess(firmwares));
  } catch (error) {
    yield put(fetchFirmwaresFailure(error.message));
  }
}

export function* watchFetchFirmwares() {
  yield takeLatest(FETCH_FIRMWARES_REQUEST, fetchFirmwares);
}
4. reducer.js
// src/store/firmware/reducer.js
import {
  FETCH_FIRMWARES_REQUEST,
  FETCH_FIRMWARES_SUCCESS,
  FETCH_FIRMWARES_FAILURE,
} from './actionTypes';

const initialState = {
  loading: false,
  firmwares: [],
  error: '',
};

const firmwareReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_FIRMWARES_REQUEST:
      return { ...state, loading: true };
    case FETCH_FIRMWARES_SUCCESS:
      return { loading: false, firmwares: action.payload, error: '' };
    case FETCH_FIRMWARES_FAILURE:
      return { loading: false, firmwares: [], error: action.payload };
    default:
      return state;
  }
};

export default firmwareReducer;

第三步:整合所有模块到Store

1. 合并所有saga(rootSaga.js)

// src/store/rootSaga.js
import { all } from 'redux-saga/effects';
import { watchFetchProducts } from './product/saga';
import { watchFetchFirmwares } from './firmware/saga';

export default function* rootSaga() {
  yield all([
    watchFetchProducts(),
    watchFetchFirmwares(),
  ]);
}

2. 合并所有reducer(rootReducer.js)

// src/store/rootReducer.js
import { combineReducers } from 'redux';
import productReducer from './product/reducer';
import firmwareReducer from './firmware/reducer';

const rootReducer = combineReducers({
  product: productReducer,
  firmware: firmwareReducer,
});

export default rootReducer;

3. 创建Store实例(index.js)

// src/store/index.js
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './rootReducer';
import rootSaga from './rootSaga';

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

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

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

export default store;

第四步:在App中注入Store

在App.js里用Provider把整个应用包裹起来,让所有组件都能访问到Store:

// App.js
import { Provider } from 'react-redux';
import store from './src/store';
import { NavigationContainer } from '@react-navigation/native';
// 导入你的页面和导航组件
import ProductScreen from './src/components/ProductScreen';
import FirmwareScreen from './src/components/FirmwareScreen';

export default function App() {
  return (
    <Provider store={store}>
      <NavigationContainer>
        {/* 这里放你的导航栈,比如StackNavigator */}
        <ProductScreen />
        <FirmwareScreen />
      </NavigationContainer>
    </Provider>
  );
}

第五步:在页面组件中使用Store

以ProductScreen为例,用useDispatch派发action,useSelector获取状态:

// src/components/ProductScreen.js
import React, { useEffect } from 'react';
import { View, Text, ActivityIndicator, StyleSheet } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { fetchProductsRequest } from '../store/product/actions';

const ProductScreen = () => {
  const dispatch = useDispatch();
  // 从store中获取Product模块的状态
  const { loading, products, error } = useSelector(state => state.product);

  // 页面加载时触发请求
  useEffect(() => {
    dispatch(fetchProductsRequest());
  }, [dispatch]);

  // 加载状态显示
  if (loading) {
    return <ActivityIndicator size="large" color="#0066cc" style={styles.loader} />;
  }

  // 错误状态显示
  if (error) {
    return <Text style={styles.errorText}>请求失败:{error}</Text>;
  }

  // 正常渲染产品列表
  return (
    <View style={styles.container}>
      {products.map(product => (
        <Text key={product.id} style={styles.productItem}>
          {product.name} - {product.price}元
        </Text>
      ))}
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, padding: 16 },
  loader: { flex: 1, justifyContent: 'center' },
  errorText: { color: 'red', textAlign: 'center', marginTop: 20 },
  productItem: { padding: 12, borderBottomWidth: 1, borderBottomColor: '#eee' },
});

export default ProductScreen;

FirmwareScreen的用法和上面完全一致,只需要替换对应的action和selector即可。


内容的提问来源于stack exchange,提问作者Reaksmey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:41:57