React中用Axios+MobX获取服务端数据遇fetchData未调用及data未定义问题
问题分析与解决方案
核心问题
- Store未实例化:你导出的是
store类而非实例,组件中直接访问store.data本质是访问类的静态属性,而data是实例属性,必然返回undefined,同时调用store.fetchData()也会失败(因为这是实例方法)。 - 依赖缺失:
store.js未导入mobx的observable、action以及axios,导致代码运行时变量未定义。 - 未处理数据加载前的空状态:组件直接访问
store.data[activeTab].name,当data为空数组时会触发额外报错。
修复步骤
1. 修正Store代码(store.js)
import { makeObservable, observable, action } from 'mobx'; import axios from 'axios'; // 导入axios class Store { // 类名建议大写,符合规范 data = [] isFetching = false error = null constructor() { makeObservable(this, { data: observable, isFetching: observable, error: observable, fetchData: action }) } fetchData() { this.isFetching = true axios.get('http://localhost:3001/data') .then(response => { this.data = response.data this.isFetching = false console.log('Success'); }) .catch(err => { this.error = err this.isFetching = false console.log('Error'); }) } } // 导出Store的实例,而非类本身 export default new Store();
2. 修正组件代码(LoginsList.js)
import React, { useState, useEffect } from 'react'; import classNames from 'classnames'; import { Observer } from 'mobx-react-lite'; import store from '../.store/data'; // 现在导入的是实例 import LoginDetails from './LoginDetails'; import Login_Icon from '../assets/icons/Login.svg' import '../assets/css/LoginCards.css' const LoginsList = () => { const [activeTab, setActiveTab] = useState(0); const [hoveredTab, setHoveredTab] = useState(null); const handleMouseEnter = (index) => { if (index !== activeTab) { setHoveredTab(index); } } const handleClick = (index) => { setHoveredTab(null); setActiveTab(index); } useEffect(() => { store.fetchData(); // 现在调用的是实例方法,会正常执行 }, []); // 获取当前选中的卡片数据,处理空状态 const currentCard = store.data[activeTab] || {}; return ( <Observer> {() => ( // Observer需要接收一个函数返回JSX,确保响应式追踪 <> {store.isFetching && <div>加载中...</div>} {store.error && <div>加载失败: {store.error.message}</div>} {store.data.length > 0 ? ( <> <ul> {store.data.map((card, index) => ( <li key={card.id} onClick={() => handleClick(index)} onMouseEnter={() => handleMouseEnter(index)} onMouseLeave={() => setHoveredTab(null)} className="LoginCard" > <div className={classNames('LoginCardContainer', { 'active-logincard': index === activeTab }, { 'hovered-logincard': index === hoveredTab })} > <img src={Login_Icon} alt="Login Icon"></img> <div className="TextZone"> <p>{card.name}</p> <div>{card.username}</div> </div> </div> </li> ))} </ul> <div> <div className="LoginDetails"> <img className="LoginDetailsIcon" src={Login_Icon}></img> </div> <LoginDetails key={activeTab} name={currentCard.name || ''} username={currentCard.username || ''} password={currentCard.password || ''} /> {currentCard.password} </div> </> ) : !store.isFetching && ( <div>暂无数据</div> )} </> )} </Observer> ); } export default LoginsList;
关键说明
- Store实例化:通过
export default new Store()导出单例实例,确保组件使用的是同一个Store对象,数据状态全局共享。 - Observer正确用法:
Observer组件需要接收一个函数作为子元素,这样MobX才能正确追踪响应式数据的变化并触发重渲染。 - 空状态处理:添加加载中、错误提示,以及数据为空时的兜底,避免访问
undefined属性导致报错。
内容的提问来源于stack exchange,提问作者Electro
相关产品推荐
相关产品推荐

