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

React-Views报错TypeError: 无法读取undefined的map属性问题

React setState后数据可控制台打印但map无法渲染的修复方案

问题现象

setState执行后可在回调中正常打印获取到的列表数据,但渲染阶段调用this.state.results.map()时报错,使用可选链this.state.results?.map()时页面无内容展示。项目使用express-react-views做服务端渲染,接口返回数据包含a、i两组对象列表。

原始问题代码

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

let display = new getPipeLine;

class ActiveLoans extends React.Component {
    constructor(props) {
       super(props)
        this.state = {
          data: display
        }; 
}; 

async componentDidMount() {
    const activeDisplay = async () => 
     await this.state.data.then((results) => {
        console.log('Data Fetched')
        !!!this.setState({results});               
    });
    activeDisplay()
};

render(){
    return(
        <React.Fragment>
                <Head />
                <Nav />
                {this.state.results.map((result) => (
                    <div key={result.a.LoanNumber}>
                        <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>{result.a.LoanNumber}</td>
                                <td>{result.a.LoanStatus}</td>
                                <td>{result.a.LoanType}</td>
                                <td>{result.a.SubmitDate}</td>
                                <td>{result.a.LastReview}</td>
                            </tr>                
                        </tbody>
                    </div>
                ))}

                
                <Footer />    
        </React.Fragment>
)}}

module.exports = ActiveLoans;

已尝试的排查操作

  • 在setState回调中打印数据,可正常输出获取结果,代码如下:
const activeDisplay = async () => 
 await this.state.data.then((results) => {
    console.log('Data Fetched')
    !!!this.setState({results}, 
        (async () => {
    let obj = await results;
    console.log('Done:', obj);
})());               
});
activeDisplay()
}; 
  • 尝试使用可选链写法调用map,页面无任何内容

接口返回数据结构示例

'0': {
  LoanNumber: 12345252,
  LoanStatus: 'Initial',        
  LoanType: 'FHA',
  SubmitDate: '1/14/2022',      
  LastReview: null
},
'1': {
  LoanNumber: 12345626,
  LoanStatus: 'Initial',        
  LoanType: 'VA',
  SubmitDate: '1/14/2022',      
  LastReview: null
},
'2': {
  LoanNumber: 12345670,
  LoanStatus: 'Initial',        
  LoanType: 'Conventional',     
  SubmitDate: '1/14/2022',      
  LastReview: null
}, 

根因分析

一共4个问题导致渲染失败:

  1. state初始值缺失:构造函数中仅初始化了data字段,首次渲染(服务端渲染阶段不会执行componentDidMount)时this.state.results为undefined,直接调用.map()会触发类型错误,阻断渲染流程。
  2. 返回值为类数组对象:接口返回的是数字键名的类数组结构,本身不存在map方法,即便setState执行成功也无法直接调用数组方法。
  3. 冗余语法干扰:!!!this.setState()属于无意义写法,setState本身无返回值,三重非运算不会改变执行逻辑,但属于错误编码习惯。
  4. DOM结构不合法:<thead>、<tbody>必须作为<table>标签的直接子元素,原代码将其放在循环生成的div中,不符合HTML规范,会导致表格渲染异常。

修复步骤

  1. 补全state初始值,给results设置空数组默认值,避免首次渲染报错
  2. 移除setState前的冗余非运算,拿到接口返回值后先将类数组结构转为标准数组,再存入state
  3. 修正表格DOM结构,将thead移出循环,外层包裹合法table标签
  4. 增加数据加载态判断,数据未返回时展示加载提示

修复后完整代码

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

let display = new getPipeLine;

class ActiveLoans extends React.Component {
    constructor(props) {
       super(props)
        this.state = {
          data: display,
          results: [] // 初始化results默认值
        }; 
    }

    async componentDidMount() {
      try {
        const rawResults = await this.state.data;
        // 类数组转标准数组,适配数组方法调用
        const results = Array.from(Object.values(rawResults));
        this.setState({results});
      } catch (err) {
        console.error('贷款数据加载失败:', err);
      }
    }

    render(){
        return(
            <React.Fragment>
                <Head />
                <Nav />
                {this.state.results.length === 0 ? (
                  <div>数据加载中...</div>
                ) : (
                  <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>
                      {this.state.results.map((result) => (
                        <tr key={result.a.LoanNumber}>
                            <td>{result.a.LoanNumber}</td>
                            <td>{result.a.LoanStatus}</td>
                            <td>{result.a.LoanType}</td>
                            <td>{result.a.SubmitDate}</td>
                            <td>{result.a.LastReview}</td>
                        </tr>                
                      ))}
                    </tbody>
                  </table>
                )}
                <Footer />    
            </React.Fragment>
        )
    }
}

module.exports = ActiveLoans;

额外注意

express-react-views做服务端渲染时不会执行组件的componentDidMount生命周期,上述修复后首屏仍会先展示加载态,客户端hydrate后才会渲染列表。如果需要首屏直出列表数据,需要在服务端调用getPipeLine拿到数据后,通过props传入组件,不要在组件生命周期内获取首屏数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:00:57