Express+React+Redux异步取数渲染异常:返回Promise而非数组
问题根源分析
你遇到的核心问题是:Redux默认的reducer是同步执行的,无法自动解析Promise。你当前的代码直接把callApi()(一个返回Promise的async函数)作为值返回给了reducer,导致你的state里存储的是Promise对象,而非实际的数组数据,这就是渲染时显示[Promise]的原因。
解决方案步骤
要处理Redux中的异步操作,我们需要借助redux-thunk中间件(它允许action创建函数返回一个函数,而非普通action对象),下面是具体的修改方案:
1. 安装并配置redux-thunk
首先安装依赖:
npm install redux-thunk # 或者用yarn yarn add redux-thunk
然后在创建Redux Store的文件中,添加thunk中间件:
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers'; // 你的根reducer const store = createStore( rootReducer, applyMiddleware(thunk) // 加入thunk中间件 ); export default store;
2. 重构异步Action创建函数
把原来直接返回Promise的逻辑,改成返回一个能dispatch同步action的函数:
// 先定义action类型常量 export const FETCH_ITEMS_SUCCESS = 'FETCH_ITEMS_SUCCESS'; // 同步action:用于把获取到的数据传给reducer export const fetchItemsSuccess = (items) => ({ type: FETCH_ITEMS_SUCCESS, payload: items }); // 异步action:由thunk处理,负责调用API并dispatch同步action export const fetchItems = () => { return async (dispatch) => { try { console.log("calling API"); const response = await fetch('/api/hello'); if (response.status !== 200) throw new Error('Failed to fetch data'); const items = await response.json(); dispatch(fetchItemsSuccess(items)); // 把数据传给reducer } catch (error) { console.error('API请求失败:', error); // 这里可以扩展错误处理逻辑,比如dispatch一个错误action } }; };
3. 修改Reducer处理新的Action
更新你的reducer-items.js,处理FETCH_ITEMS_SUCCESS类型的action:
import { FETCH_ITEMS_SUCCESS } from '../actions/index'; // 初始状态设为空数组,避免渲染时报错 const initialState = []; export default function itemsReducer(state = initialState, action) { switch (action.type) { case FETCH_ITEMS_SUCCESS: return action.payload; // 用API返回的数组更新state default: return state; } }
4. 在组件中触发异步Action
修改你的ItemList组件,在组件挂载时调用异步action获取数据,并添加加载状态判断:
import React, {Component} from 'react'; import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import { selectedItem, fetchItems } from '../actions/index'; // 导入fetchItems class ItemList extends Component { // 组件挂载时触发API请求 componentDidMount() { this.props.fetchItems(); } renderList() { // 如果数据还没加载完成,显示加载提示 if (!this.props.items.length) { return <li>Loading items...</li>; } return this.props.items.map((item) => { return ( <li key={item.id} onClick={() => this.props.selectedItem(item)}> {item.first} {item.last} </li> ); }); } render() { console.log("render", this.props.items); return ( <ul> {this.renderList()} </ul> ); } } function mapStateToProps(state) { return { items: state.items }; } function matchDispatchToProps(dispatch) { return bindActionCreators({ selectedItem: selectedItem, fetchItems: fetchItems // 把异步action加入dispatch绑定 }, dispatch); } export default connect(mapStateToProps, matchDispatchToProps)(ItemList);
为什么原来的代码不生效?
你的原代码中,export default function () { return [callApi()] }返回的是一个包含Promise的数组——因为async函数默认会返回Promise,而Redux的reducer是纯同步函数,不会等待Promise resolve,所以state里存储的就是未解析的Promise对象,而非你期望的数组数据。
内容的提问来源于stack exchange,提问作者David Pishchik
相关产品推荐
相关产品推荐

