【问题标题】:Action does not trigger a reducer in Redux在 Redux 中 Action 不会触发 reducer
【发布时间】:2019-01-18 05:25:44
【问题描述】:

我是 redux 的新手,正在尝试使用 Contentful API 获取内容。由于某种原因,我调用的操作没有到达减速器。我附上了我认为相关的代码,任何贡献都将受到高度赞赏。

actions/index.js

import axios from 'axios';

const API_BASE_URL = 'https://cdn.contentful.com';
const API_SPACE_ID = 'xxxxxxxxxxxxx';
const API_KEY ='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

const FETCH_CONTENT = 'fetch_content';

export function fetchContent() {
  const request = axios.get(`${API_BASE_URL}/spaces/${API_SPACE_ID}/environments/master/entries?access_token=${API_KEY}`);
  return {
    type: FETCH_CONTENT,
    payload: request
  };
  }

reducers/index.js

import { combineReducers } from 'redux';
import ContentReducer from './reducer-content';

const rootReducer = combineReducers({
  contents: ContentReducer
});

export default rootReducer;

reducer-content.js

import {FETCH_CONTENT} from '../actions';
const INITIAL_STATE = { all: [] };

export default function(state = INITIAL_STATE, action){
  switch(action.type){
    case FETCH_CONTENT:
      return { ...state, all: action.payload.data.items };

  default:
  return state;
  }
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route, Switch } from "react-router-dom";
import promise from 'redux-promise';
import { logger } from 'redux-logger'


import ContentIndex from './components/content-index';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(promise, logger)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <BrowserRouter>
      <div>
      <Route  path = "/" component = {ContentIndex}/>
    </div>
    </BrowserRouter>

  </Provider>
  , document.querySelector('.container'));

组件/内容索引.js

import React, {Component} from 'react';
import {fetchContent} from '../actions';
import {connect} from 'react-redux';
import _ from 'lodash';

class ContentIndex extends Component {
  componentDidMount(){
    this.props.fetchContent();
  }

  renderContent(props){
    return this.props.contents.map((content, index) => {
      return (
        <article key={content.sys.id}>
          <h3>{content.fields.name}</h3>
          <p>{content.fields.website}</p>
        </article>
      );
    });
  }

  render(){
    return(
      <div>
      <h3>Content</h3>
      {this.renderContent()}
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {contents: state.contents.all};
}
// export default CharacterIndex;
export default connect(mapStateToProps, {fetchContent})(ContentIndex);

【问题讨论】:

  • 就像 devserkan 说的,你需要一个异步操作,因为 axios 总是返回承诺,而不是直接返回响应的数据。异步函数是处理这个问题的最简单方法,但您需要在 redux 中拥有正确的中间件。
  • 看来redux-promise 在等待一个promise,我猜错了。所以,当你在你的 action creator 和 reducer 中添加 console.log 时,它在哪里失败了?我的意思是它在哪里停止被记录?

标签: reactjs redux redux-promise


【解决方案1】:

更新

看来我在这里错了(感谢@Dave Newton 的 cmets)。 redux-promise 等待一个承诺,如果它收到一个承诺,则解决它并分派该值。所以,在这里使用 async 函数和使用 action creator 是没有用的。


您正在使用redux-promise,我不知道它是如何处理这种情况的,但在其 Github 存储库中有一个 redux-actions 的示例,它使用异步函数。我对redux-thunk 更熟悉,但在您的情况下,在这里使用异步操作创建器可能更合适。

试试这个:

export async function fetchContent() {
  const request = await axios.get(`${API_BASE_URL}/spaces/${API_SPACE_ID}/environments/master/entries?access_token=${API_KEY}`);
  return {
    type: FETCH_CONTENT,
    payload: request
  };
}

【讨论】:

  • 在 redux-promise 中,它期望有效载荷是承诺;当 promise 解决时,reducer 会使用已解决的 promise 调用(但如果它拒绝则不会)。在这里,您只是创建了一个正常的操作,这很好,但会使 redux-promise 毫无意义。
  • @DaveNewton,我错了吗?首先,我怀疑但在看到redux-actions 示例后,我认为它需要解析的数据。 github.com/redux-utilities/redux-promise
  • "如果它接收到一个 Promise,它将分发该 Promise 的解析值。如果该 Promise 拒绝,它不会分发任何东西。"如果您执行异步/等待,您只是在创建常规(异步)操作。这很好,但是让 redux-promise 看起来不再那么有用了。 (尽管我出于其他原因停止使用 redux-promise,但它在一段时间内还是一个有用的抽象。)
  • 知道了。我错过了那部分并浏览了这个例子。这让我很困惑。我将更新我的答案。谢谢!
  • @devserkan 我认为现在对我来说一切都有意义。但是,我在控制台中没有收到错误消息:未捕获的 ReferenceError: regeneratorRuntime is not defined。
【解决方案2】:

axios.get() 返回承诺。

所以你需要使用 async / await。

【讨论】:

    【解决方案3】:

    您可以通过执行以下操作来简化代码并避免调度异步操作和需要使用 redux 中间件:

    • fetchContent() 转换为异步函数,该函数返回带有有效负载中项目的操作
    • 创建一个mapDispatchToProps,它创建一个函数来调度fetchContent()返回的操作

    fetchContent() 看起来像这样:

    export async function fetchContent() {
      const request = await axios.get(`${API_BASE_URL}/spaces/${API_SPACE_ID}/environments/master/entries?access_token=${API_KEY}`);
      return {
        type: FETCH_CONTENT,
        payload: request.data.items
      };
    }
    

    connect 看起来像这样:

    const mapStateToProps = (state) => {
      return {contents: state.contents.all};
    }
    
    const mapDispatchToProps = (dispatch) => {
      return {
        loadItems: () => fetchContent().then(action => dispatch(action))
      }
    }
    
    // export default CharacterIndex;
    export default connect(mapStateToProps, mapDispatchToProps)(ContentIndex);
    

    你的减速器看起来像这样:

    export default function(state = INITIAL_STATE, action){
      switch(action.type){
        case FETCH_CONTENT:
          return { ...state, all: action.payload };
    
      default:
      return state;
      }
    }
    

    componentDidMount() 看起来像这样:

      componentDidMount(){
        this.props.loadItems();
      }
    

    【讨论】:

    • @JaredMudd 友好提醒,如果它提供了所需的信息,请接受答案
    猜你喜欢
    • 2016-08-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2023-03-03
    • 2019-05-16
    • 2018-11-08
    • 2020-01-15
    • 2018-09-03
    相关资源
    最近更新 更多