如果注入不同的容器,Redux Sagas会多次射击

时间:2018-01-03 18:10:02

标签: reactjs redux redux-saga

我们正在使用https://github.com/react-boilerplate/react-boilerplate并拥有包含多个组件的经典商店布局。

我们有一个用于向购物车添加产品的redux商店,它具有副作用传奇,可以将添加的产品保存到购物车数据库。

由于有多个职位要将产品添加到购物车,我们在一个页面上使用了相同的CartContainer 3次(购物车本身,产品列表和另一个产品列表)。

我们现在遇到的问题是,api会被调用3次。

我想这是因为,通过使用容器3次,我们还注射了Saga三次。

我现在的问题是: 什么是只注射一次传奇的正确方法,而不必一次又一次地重写所有的传奇?

这是我的传奇:

import {
  call,
  put,
  select,
  takeLatest,
} from 'redux-saga/effects';
import {getRequest, putRequest} from '../../utils/request';

import {ADD_PRODUCT, LOAD_PRODUCTS} from './constants';
import {
  addProductSuccess,
  addProductError,
  productsLoaded,
  productsLoadingError,
} from './actions';
import {makeSelectProduct, makeSelectUserId} from './selectors';


/**
 * Github repos request/response handler
 */
export function* getProducts() {
  const requestURL = '/api/orders';
  const user_id = yield select(makeSelectUserId());
  try {
    let itemsData = yield call(getRequest, requestURL, user_id);
    if (itemsData) {
      itemsData = itemsData.slice(-1).items;
    }
    yield put(productsLoaded(itemsData));
  } catch (err) {
    yield put(productsLoadingError(err));
  }
}

/**
 * Github repos request/response handler
 */
export function* addProduct() {
  const requestURL = '/api/cart';
  const productData = yield select(makeSelectProduct());

  try {
    const orderData = yield call(putRequest, requestURL, productData);
    yield put(addProductSuccess(orderData.id));
  } catch (err) {
    yield put(addProductError(err));
  }
}

/**
 * Root saga manages watcher lifecycle
 */
export default function* root() {
  yield [
    takeLatest(ADD_PRODUCT, addProduct),
    takeLatest(LOAD_PRODUCTS, getProducts),
  ];
}

这是我的容器的导出部分:

export function mapDispatchToProps(dispatch) {
  return {
    onAddProduct: (id, quantity, variant) => {
      dispatch(addProduct(id, quantity, variant));
    },
    onLoadProducts: (user_id) => {
      dispatch(loadProducts(user_id));
    },
  };
}

const mapStateToProps = createStructuredSelector({
  products: makeSelectProducts(),
});

const withConnect = connect(mapStateToProps, mapDispatchToProps);

const withReducer = injectReducer({key: 'cart', reducer});
const withSaga = injectSaga({key: 'cart', saga});


export default compose(withReducer, withConnect)(CartContainer);

2 个答案:

答案 0 :(得分:6)

你必须改变注射你的传奇的方式,这样它才会被注射一次。

containers/App/index.js

// ...
import { compose } from 'redux';
import injectSaga from 'utils/injectSaga';
import injectReducer from 'utils/injectReducer';
import reducer from 'containers/CartContainer/reducer';
import saga from 'containers/CartContainer/saga';

function App() { // We don't change this part
  // ...
}


// Add this lines
const withReducer = injectReducer({ key: 'cartContainer', reducer });
const withSaga = injectSaga({ key: 'cartContainer', saga });

export default compose(
  withReducer,
  withSaga,
)(App);

现在在你的`containers / CartContainer / index.js``

import React from 'react':

// ...

class CartContainer extends React.Component {
  // ...
}

const withConnect = connect(mapStateToProps, mapDispatchToProps);

// REMOVE THIS LINES //
// const withReducer = injectReducer({ key: 'cartContainer', reducer });
// const withSaga = injectSaga({ key: 'cartContainer', saga });

export default compose(
 // withReducer,
 // withSaga,
 withConnect,
)(CartContainer);

答案 1 :(得分:1)

我猜你使用的redux-sagas-injector对我来说总是很奇怪。该传奇在React组件内部或周围没有任何位置。对我来说,它看起来像一个反模式。您的组件应该只调度操作,而侦听这些操作的传奇应该只处理副作用。我建议您在一个地方初始化您的redux商店,不要使用injectReducerinjectSaga

P.S。 抱歉,我看到mapDispatchToPropsmapStateToProps旁边的传奇和减速器看起来很奇怪。