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

express-react-views下setState与componentDidMount更新异常问题

核心问题

你遇到的问题是两个层面的错误叠加导致的:

  1. 渲染引擎机制问题:你用的express-react-views是纯静态服务端渲染引擎,服务端渲染阶段只会执行组件构造函数、render方法,完全不会触发componentDidMount这类仅客户端运行的生命周期钩子,服务端生成完静态HTML就直接返回给浏览器了,根本不会等待你写在生命周期里的异步请求完成,也不会在状态更新后重新执行render。
  2. 代码逻辑错误:就算放到纯客户端React环境下,你现有代码也无法正常渲染,存在以下硬伤:
    • 遍历数据时错把类方法this.getData(本身是函数)当成了数据源,Array.isArray(this.getData)永远返回false,自然不会渲染列表内容,你存到this.state.FinalData里的数据从来没被render读取过。
    • setState的第二个参数要求传回调函数引用,你写的是立即执行的自执行异步函数,等于回调逻辑在setState调用时就立刻跑了,只是闭包拿到了接口返回值所以打印看起来正常,实际上和setState是否完成更新没有关系。
    • render函数里绝对不能直接调用会触发setState的异步方法,你在render里调用this.getData()会触发无限重渲染循环,属于React基础写法错误。
    • componentDidMount里第一次调用getData时传入的FinalData变量根本没有定义,会直接抛出引用错误;且重复调用了两次getData发起重复请求。
    • 接口返回的列表数据存在返回值的a字段下,你没有读取对应字段,初始状态FinalData设为空对象也不符合列表遍历的预期。
修复方案

根据你的渲染场景二选一即可:

方案1:继续使用express-react-views做纯静态SSR

这种场景下不要在组件内部写任何异步拉数逻辑,所有数据必须在路由层提前查询完成,再通过props传入组件:

  1. 路由层修改:
// 对应路由文件
const express = require('express');
const router = express.Router();
const getPipeLine = require('../../service/Contructor.js');

router.get('/active-loans', async (req, res, next) => {
  try {
    const display = new getPipeLine();
    const finalData = await display;
    // 提前拿完所有数据,作为props传给待渲染组件
    res.render('ActiveLoans', { FinalData: finalData });
  } catch (err) {
    next(err)
  }
});

module.exports = router;
  1. 组件层简化,去掉所有无效的生命周期、拉数方法,直接从props读数据渲染:
const React = require('react');
const Head = require('../components/Head.jsx');
const Nav = require('../components/Nav.jsx');
const Footer = require('../components/Footer.jsx');

class ActiveLoans extends React.Component {
  render() {
    // 从props取路由传入的数据,拿a字段下的贷款列表,做兜底处理
    const loanList = this.props.FinalData?.a || [];
    return (
      <React.Fragment>
        <Head />
        <Nav />
        {loanList.map((item) => (
          <div key={item.LoanNumber}>
            <table>
              <thead>
                <tr>
                  <th>Loan Number</th>
                  <th>Loan Status</th>
                  <th>Loan Type</th>
                  <th>Submit Date</th>
                  <th>Last Review</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>{item.LoanNumber}</td>
                  <td>{item.LoanStatus}</td>
                  <td>{item.LoanType}</td>
                  <td>{item.SubmitDate}</td>
                  <td>{item.LastReview}</td>
                </tr>
              </tbody>
            </table>
          </div>
        ))}
        <Footer />
      </React.Fragment>
    )
  }
}

module.exports = ActiveLoans;

方案2:需要客户端动态拉数/交互

这种场景不要用express-react-views渲染当前页面,改成前后端分离模式:客户端加载React打包后的JS bundle,由客户端完成渲染、拉数逻辑,此时componentDidMount才会正常触发。客户端组件正确写法参考:

const React = require('react');
const Head = require('../components/Head.jsx');
const Nav = require('../components/Nav.jsx');
const Footer = require('../components/Footer.jsx');
const getPipeLine = require('../../service/Contructor.js');

class ActiveLoans extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      loanList: [],
      loading: true
    };
  }

  async componentDidMount() {
    try {
      const display = new getPipeLine();
      const resData = await display;
      this.setState({
        loanList: resData.a || [],
        loading: false
      }, () => {
        console.log('状态更新完成', this.state.loanList)
      })
    } catch (err) {
      console.log(err.message)
      this.setState({loading: false})
    }
  }

  render() {
    const { loanList, loading } = this.state;
    if (loading) return <div>数据加载中...</div>
    
    return (
      <React.Fragment>
        <Head />
        <Nav />
        {loanList.map((item) => (
          <div key={item.LoanNumber}>
            <table>
              <thead>
                <tr>
                  <th>Loan Number</th>
                  <th>Loan Status</th>
                  <th>Loan Type</th>
                  <th>Submit Date</th>
                  <th>Last Review</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>{item.LoanNumber}</td>
                  <td>{item.LoanStatus}</td>
                  <td>{item.LoanType}</td>
                  <td>{item.SubmitDate}</td>
                  <td>{item.LastReview}</td>
                </tr>
              </tbody>
            </table>
          </div>
        ))}
        <Footer />
      </React.Fragment>
    )
  }
}

module.exports = ActiveLoans;

注意:你给出的目标数据示例本身结构不完整,a字段对应的对象缺少闭合括号,实际使用时注意确认接口返回的最终结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 00:18:24