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

zec*_*ude 4 javascript reactjs redux-saga

我是redux-saga的新手,我正在尝试一个简单的演示工作,它会进行API调用并将响应数据发送到reducer,以便将其保存到商店.据我所知,redux-saga流应该如下工作.

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


在此输入图像描述


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


组件/ 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);
Run Code Online (Sandbox Code Playgroud)


动作/ index.js

import axios from 'axios';

export const FETCH_POSTS = 'FETCH_POSTS';

export const fetchPosts = () => {
  console.log('fetchPosts() in actions');

  return {
    type: FETCH_POSTS
  };
};
Run Code Online (Sandbox Code Playgroud)


传奇/ 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()];
}
Run Code Online (Sandbox Code Playgroud)


减速器/ 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;
};
Run Code Online (Sandbox Code Playgroud)


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

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

mar*_*son 11

Sagas 不会阻止行动到达减速器.传奇中间件显然相当于:

next(action); // pass the action onwards to the reducers
processSagas(action);
Run Code Online (Sandbox Code Playgroud)

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

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