You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MERN(替换Mongo为MySQL)应用中React整合异步后端调用问题

问题分析与解决方案

先拆解你代码里的几个核心问题:

  1. 异步时序错误:context.query是异步操作,你的return result写在它外面,会在数据库查询完成前就执行,所以这个返回值永远是undefined。
  2. 模块导出的误解:module.exports.stocks是在模块加载阶段就被确定的,异步回调里给它赋值的时候,前端早就已经导入了这个空变量,自然拿不到数据。而且前后端是分离的——React运行在浏览器里,后端代码运行在服务器上,两者得通过HTTP API通信,不能直接在React里导入Node.js后端的模块变量。
  3. 回调使用不当:throw err会直接导致Node.js进程崩溃,应该把错误传递给回调而非抛出;另外callback(err, result)的返回值赋值给stocks完全没必要,回调本身就是用来传递结果的。

正确的后端实现(Express + MySQL)

方式1:改用Promise/Async-Await(推荐,代码更易维护)

先把数据库查询封装成Promise,再结合Express创建API接口:

// 封装MySQL查询为Promise
function queryPromise(context, sql) {
  return new Promise((resolve, reject) => {
    context.query(sql, (err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
}

// 异步获取所有股票
async function getAllStocks() {
  const context = dbContext.create();
  try {
    const result = await queryPromise(context, `SELECT * from Stock`);
    context.end(); // 记得关闭数据库连接
    return result;
  } catch (err) {
    context.end();
    throw err; // 把错误抛给上层路由处理
  }
}

// 注册Express路由
const express = require('express');
const router = express.Router();

router.get('/api/stocks', async (req, res) => {
  try {
    const stocks = await getAllStocks();
    res.status(200).json(stocks);
  } catch (err) {
    console.error('获取股票失败:', err);
    res.status(500).json({ error: '服务器内部错误' });
  }
});

module.exports = router;

方式2:如果坚持用回调(不推荐,易陷入回调地狱)

如果一定要保留回调写法,至少要保证回调的正确传递,且不要试图导出动态变量:

function getAllStocks(callback) {
  const context = dbContext.create();
  context.query(`SELECT * from Stock`, (err, result) => {
    context.end();
    if (err) {
      console.error('查询错误:', err);
      return callback(err, null); // 把错误传给回调,避免进程崩溃
    }
    callback(null, result);
  });
}

// 绑定路由
router.get('/api/stocks', (req, res) => {
  getAllStocks((err, stocks) => {
    if (err) {
      res.status(500).json({ error: '获取股票失败' });
      return;
    }
    res.status(200).json(stocks);
  });
});

前端React的调用方式

后端有了API接口后,React里可以用fetch或axios请求数据,结合useState和useEffect管理状态:

import { useState, useEffect } from 'react';

function StockList() {
  const [stocks, setStocks] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchStocks = async () => {
      try {
        // 替换成你的后端API地址
        const response = await fetch('http://localhost:3001/api/stocks');
        if (!response.ok) throw new Error('请求失败');
        const data = await response.json();
        setStocks(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchStocks();
  }, []);

  if (loading) return <div>加载中...</div>;
  if (error) return <div>错误: {error}</div>;

  return (
    <ul>
      {stocks.map(stock => (
        <li key={stock.id}>{stock.name} - {stock.price}</li>
      ))}
    </ul>
  );
}

export default StockList;

关键注意事项

  • 前后端分离原则:永远不要试图在React里直接导入Node.js后端的模块变量,必须通过HTTP API通信。
  • 数据库连接管理:每次查询后记得关闭连接,或者使用连接池(更推荐),避免连接泄漏。
  • 错误处理:后端和前端都要做好错误捕获,不要直接抛出错误导致进程崩溃或页面白屏。

内容的提问来源于stack exchange,提问作者Randy Quackers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 18:52:48