使用React,为什么redux传奇不会拦截行动?

时间:2017-10-23 04:02:14

标签: javascript reactjs redux-saga

我对redux-saga非常陌生,我正试图让simple demo工作,进行API调用并将响应数据发送到reducer,以便将其保存到商店。据我所知,redux-saga流应该如下工作。

  1. 组件调用操作创建者
  2. 然后,动作创建者会使用特定类型
  3. 发出动作
  4. 守望者sagas都会监听所发出的任何动作,并拦截它正在侦听的动作。然后它调用适当的工人传奇。
  5. worker saga进行API调用,并使用action类型和有效负载将操作分派给reducers。
  6. reducer侦听任何已调度的操作,如果匹配,则使用提供的数据更新存储中的状态。

  7. enter image description here


    我已经制定了我的代码来遵循这个流程,但事情并没有正常工作。让我展示我的代码,然后我将详细说明问题。


    组件/ PostsIndex.js

    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    import { fetchPosts } from '../actions';
    
    class PostsIndex extends Component {
      componentDidMount() {
        this.props.fetchPosts();
      }
    
      renderPosts() {
        console.log(this.props.posts);
      }
    
      render() {
        return (
          <div>
            {this.renderPosts()}
          </div>
        );
      }
    }
    
    const mapStateToProps = state => ({
        posts: state.posts
      });
    
    export default connect(mapStateToProps, { fetchPosts })(PostsIndex);
    


    操作/ index.js

    import axios from 'axios';
    
    export const FETCH_POSTS = 'FETCH_POSTS';
    
    export const fetchPosts = () => {
      console.log('fetchPosts() in actions');
    
      return {
        type: FETCH_POSTS
      };
    };
    


    传奇/ index.js

    import 'regenerator-runtime/runtime';
    import { call, put, takeEvery, takeLatest } from 'redux-saga/effects';
    import axios from 'axios';
    import { FETCH_POSTS } from '../actions';
    
    const ROOT_URL = 'https://reduxblog.herokuapp.com/api';
    const API_KEY = '?key=asdsd1234';
    
    // Watcher sagas
    // Listen for an action and run the appropriate Worker saga
    export function* watchFetchPosts() {
      yield takeEvery(FETCH_POSTS, workFetchPosts);
    }
    
    // Worker sagas
    // Respond to the actions that are caught by the watcher sagas
    export function* workFetchPosts() {
      try {
        console.log('workFetchPosts() in sagas');
    
        // Try to call the API
        console.log('Attempting to call the posts API');
        const uri = `${ROOT_URL}/posts${API_KEY}`;
        const response = yield call(axios.get, uri);
        console.log('Fetched Posts Response in saga worker: ', response);
        yield put({
          type: FETCH_POSTS,
          payload: response
        });
      } catch (error) {
        // Act on the error
        console.log('Request failed! Could not fetch posts.');
        console.log(error);
      }
    }
    
    // Root sagas
    // Single entry point to start all sagas at once
    export default function* rootSaga() {
      console.log('redux saga is running');
      yield [watchFetchPosts()];
    }
    


    减速器/ PostsReducer.js

    import { mapKeys } from 'lodash';
    import { FETCH_POSTS } from '../actions';
    
    export default (state = {}, action) => {
      switch (action.type) {
        case FETCH_POSTS:
        console.log(action);
          // Create a new state object that uses an AJAX request response and grabs the 'id' property from each object in the response to use as its key
          return mapKeys(action.payload.data, 'id');
      }
    
      return state;
    };
    


    似乎减速器仍然在拾取所发出的动作,这是错误的。我注意到如果我在动作创建器中运行AJAX调用,那么传奇将会运行,但是传奇应该拦截动作创建者和减速器之间的通信,因此某些东西没有设置得非常正确。有什么想法吗?

    我的工作流程的完整环境可以在https://stackblitz.com/edit/react-redux-saga-demo进行编辑。可能更容易在那里看到问题。

1 个答案:

答案 0 :(得分:10)

Sagas不会 停止接触减速器的行动。传奇中间件明确地做了相同的:

next(action); // pass the action onwards to the reducers
processSagas(action);

因此,减速器将始终首先看到一个动作,之后传奇行为将会被激活。

另一个问题是,您似乎尝试使用相同的操作类型来触发传奇中的提取行为,处理reducer中的结果。我发现如果你使用的是sagas,你通常会有一些行为是“信号”意味着触发传奇行为,而其他行动则是由减压器和更新状态实际处理的。因此,在您的情况下,我建议使用"FETCH_POSTS"作为启动提取的信号,然后让saga在收到数据后调度"FETCH_POSTS_SUCCESS"并让reducer响应该操作。 (并且,在注意到你有StackBlitz示例之后,我确认只是将结果调度为"FETCH_POSTS_SUCCESS"确实可以正常工作,因为我也期望它。)