【问题标题】:Reducer not updating state on action being fired and hence redux store/state not being updatedReducer 不会在触发动作时更新状态,因此不会更新 redux 存储/状态
【发布时间】:2020-01-09 07:20:56
【问题描述】:

从 mediaSagas.js 触发的操作未进入减速器函数,因此减速器存储/状态未更新。 我已经尝试调试,但无法找到根本原因。

actionTypes.js

export const FLICKR_IMAGES_SUCCESS = 'FLICKR_IMAGES_SUCCESS';
export const SHUTTER_VIDEOS_SUCCESS = 'SHUTTER_VIDEOS_SUCCESS';

imageReducer.js

import initialState from './initialState';
import * as types from '../constants/actionTypes';

export default function (state = initialState.images, action) {
  console.log("action",action); // I am not getting action with type FLICKR_IMAGES_SUCCESS or SHUTTER_VIDEOS_SUCCESS
  switch (action.type) {
    case types.FLICKR_IMAGES_SUCCESS:
      return [...state, action.images];
    default:
      return state;
  }
}

videoReducer.js

import initialState from './initialState';
import * as types from '../constants/actionTypes';

export default function (state = initialState.videos, action) {
  console.log("action",action); // I am not getting action with type FLICKR_IMAGES_SUCCESS or SHUTTER_VIDEOS_SUCCESS
  switch (action.type) {
    case types.SHUTTER_VIDEOS_SUCCESS:
      return [...state, action.videos];
    default:
      return state;
  }
}

initialState.js

export default {
  images: [],
  videos: []
};

mediaSagas.js

import { put, call } from 'redux-saga/effects';
import { unsplashImages, shutterStockVideos } from '../Api/api';
import * as types from '../constants/actionTypes';


export default function* searchMediaSaga({ payload }) {
  console.log("saga entered");
  try {
    const videos = yield call(shutterStockVideos, payload);
    const images = yield call(unsplashImages, payload);
    console.log("vids",videos); // I am getting the videos data here
    console.log("img",images); // I am getting the image data here
    yield [
      put({ type: types.SHUTTER_VIDEOS_SUCCESS, videos }),
      put({ type: types.FLICKR_IMAGES_SUCCESS,images}),
    ];
  } catch (error) {
    console.log("err",error);
    yield put({ type: 'SEARCH_MEDIA_FAILURE', error });
  }
}

watchers.js

import { takeLatest } from 'redux-saga/effects';
import  searchMediaSaga  from './mediaSagas';
import * as types from '../constants/actionTypes';

// Watches for SEARCH_MEDIA_REQUEST action type asynchronously
export default function* watchSearchMedia() {
  yield takeLatest(types.SEARCH_MEDIA_REQUEST, searchMediaSaga);
}

reducers/index.js

import { combineReducers } from 'redux';
import images from './imageReducer';
import videos from './videoReducer';

const rootReducer = combineReducers({
  images, 
  videos
});

export default rootReducer;

sagas/index.js

import { fork } from 'redux-saga/effects';
import watchSearchMedia from './watchers';

export default function* startForman() {
  yield fork(watchSearchMedia);
}

configureStore.js

import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from '../reducers/index';
import rootSaga from '../sagas'; // TODO: Next step

const configureStore = () => {
  const sagaMiddleware = createSagaMiddleware(); 
  return {
    ...createStore(rootReducer,
      applyMiddleware(sagaMiddleware)),
    runSaga: sagaMiddleware.run(rootSaga)
  };
};

export default configureStore;

src/index.js

import ReactDOM from 'react-dom';
import React from 'react';
import {
  BrowserRouter as Router,
  Route,
  Switch
} from "react-router-dom";
import { Provider } from 'react-redux';
import configureStore from './store/configureStore';
import App from './containers/App'
import MediaGalleryPage from './containers/MediaGalleryPage'

const store = configureStore();
store.subscribe(() => {
  const newState = store.getState();
  // check out your updated state
  console.log("NewState", newState) // always giving empty image and video arrays
});

ReactDOM.render(
  <Provider store={store}>
    <Router>
      <Switch>  
        <Route exact path="/" component={App} />
        <Route path="/library" component={MediaGalleryPage} />
      </Switch>
    </Router>
  </Provider>, document.getElementById('root')
);

【问题讨论】:

  • saga 被调用了吗?
  • @elvis_ferns : 是的 saga 正在被调用并且正在从 API 获取数据

标签: reactjs redux react-redux redux-saga


【解决方案1】:

我发现了问题,在 mediaSagas.js 中,我并行使用了 put 效果,但现在不推荐使用我使用的方式。 Check all([...effects]) - redux saga 文档中的并行效果解决了我的问题。

我在上面使用的已弃用方式 -

yield [
      put({ type: types.SHUTTER_VIDEOS_SUCCESS, videos }),
      put({ type: types.FLICKR_IMAGES_SUCCESS,images}),
    ];

解决我的问题的新方法(正确方法)

yield all([
      put({ type: types.SHUTTER_VIDEOS_SUCCESS, videos }),
      put({ type: types.FLICKR_IMAGES_SUCCESS,images })
    ]);

Github 链接指向我的解决方案 - https://github.com/redux-saga/redux-saga/issues/459

【讨论】:

  • 并行使用put效果有什么用??
  • @elvis_ferns:根据文档定义 all 效果 - 创建一个效果描述,指示中间件并行运行多个效果并等待所有效果完成。它与标准 Promise#all 完全对应。我没有单独编写 put 效果并等待它们中的每一个,而是并行使用 put ,因为无论如何我需要等待它们都完成
  • 并行不代表并发。状态将在不同的滴答声中触发
  • 我不确定状态将如何更新,但我使用 put effect 并行/yieldall 的原因是因为我的多个 put 不相互依赖要完成,它们可以一次全部触发。如果有依赖,我会单独使用 yield put
猜你喜欢
  • 2019-05-07
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
  • 2021-10-17
  • 1970-01-01
  • 2021-07-03
  • 2019-07-28
  • 2023-01-26
相关资源
最近更新 更多