用于简单异步请求的 Redux Thunk

Redux Thunk for simple async requests

我正在构建一个简单的应用程序来从 API URL 中检索一些食谱。 我正在阅读 Thunk 的文档来实现它,但我不明白如何设置异步获取请求。 奇怪的是,如果我 console.log 将 action 传递给 reducer,它肯定会检索到正确的对象(鸡丝食谱列表)。 相反,当我将操作传递给减速器时,它会抛出错误:

"Unhandled Rejection (Error): Given action "FETCH_RECIPES", reducer "recipes" return未定义。要忽略一个动作,你必须明确地 return 以前的状态。如果你想要这个 reducer 不持有任何价值,你可以 return null 而不是 undefined。

我的 action creator 有什么错误吗? API 调用是否正确完成?

商店

import React from 'react';
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import SearchBar from './components/App';
import thunk from 'redux-thunk';
import 'bootstrap/dist/css/bootstrap.css';



import rootReducer from './reducers';

const store = createStore(rootReducer, applyMiddleware(thunk));

render(
    <Provider store={store}>
      <SearchBar />
    </Provider>,
    document.getElementById('root')
  )

组件

import React, { Component } from 'react';
import { connect } from 'react-redux';
import './App.css';
import { Button } from 'reactstrap';
import { Form } from 'reactstrap';
import { bindActionCreators } from 'redux';
import  {fetchRecipe } from '../actions';

class SearchBar extends Component {
  constructor(props) {
    super(props)


    this.state = { term: ''};
    this.typeRecipe = this.typeRecipe.bind(this)
    this.onFormSubmit = this.onFormSubmit.bind(this);  
  }

  onFormSubmit(e) {
    e.preventDefault()

    this.props.fetchRecipe(this.state.term)
  }


  typeRecipe(e) {
    this.setState({term: e.target.value});

  }

  render() {
    return (
      <div className="SearchBar">
         <Form onSubmit={this.onFormSubmit}>
            <input type='text'
            value={this.state.term}
            placeholder='ciao'
            onChange={this.typeRecipe}
             />
             <br/>
            <Button id='ciao' className='btn-success'>Submit</Button>
         </Form>
      </div>
    );
  }
}


function mapDispatchToProps(dispatch) {
  return bindActionCreators({ fetchRecipe }, dispatch);
}


export default connect(null, mapDispatchToProps)(SearchBar);

动作创作者

import axios from 'axios';

export const FETCH_RECIPES = 'FETCH_RECIPES';


const API_KEY = 'xxx';//not the real one.

export function fetchRecipe() {
   const request = axios.get(`http://food2fork.com/api/search?key=${API_KEY}&q=shredded%20chicken`);

   return (dispatch) => {
    request.then(({data}) =>{
        dispatch({ type: FETCH_RECIPES, payload: data})
    })
}


}

减速器

import { FETCH_RECIPES } from '../actions';

export default function (state = {}, action) {
    switch(action.type) {
        case FETCH_RECIPES:
            const newState = action.payload.data;                    
            return newState;
        default:
            return state
 }
}

combineReducer(索引)

import recipeReducer from '../reducers/recipes_reducer';
import { combineReducers } from 'redux';

const rootReducer = combineReducers({
    recipes: recipeReducer 
});

export default rootReducer;

reducer return 语句中有错误。

export default function (state = {}, action) {
    switch(action.type) {
        case FETCH_RECIPES:
            const newState = {...state, data : action.payload.data};                    
            return newState;
        default:
            return state
 }
}

这里我们将 data 键添加到 reducer 状态,要访问它,您可以在容器中使用:

export default connect((state)=>{
    var mapStateToProps = {};
    if(state.recipes.data) {
        mapStateToProps['recipes'] =  state.recipes.data
    }
    return mapStateToProps;    

 }, mapDispatchToProps)(SearchBar);

食谱数据将以 this.props.recipes 的形式提供。