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

React中使用Axios请求后端后数组缺失元素问题排查

问题描述

使用ReactJS结合Axios从后端获取数据,经Postman验证后端应返回包含5个元素的数组,但出现以下异常:

  • 控制台打印response.data.data时,展开前显示为5个元素的数组,展开后只剩4个
  • 单独打印数组索引0到4的元素时,能获取到“缺失”的那个元素,同时元素顺序存在异常
  • 无法确定是否为Axios的Bug

相关代码

获取消息的API函数

export const getRoomMessages = async (chatRoomId, limit = 20, page = 1) => {
  try {
    const response = await backendApi.get(
      `/chat_rooms/${chatRoomId}/chat_room_messages?limit=${limit}&page=${page}`,
    );
    console.log('reponse', response.data.data);
    console.log('data0', response.data.data[0]);
    console.log('data1', response.data.data[1]);
    console.log('data2', response.data.data[2]);
    console.log('data3', response.data.data[3]);
    console.log('data4', response.data.data[4]);
    return [null, response.data];
  } catch (e) {
    return [e, null];
  }
};

组件状态更新代码

componentDidMount() {
  this.initialFetch();
  this.connectToWebSocket();
}

componentWillUnmount() {
  this.disconnectFromWebsocket();
}

initialFetch = async () => {
  this.fetchRoomDetail();
  this.fetchMessages();
};


fetchMessages = async () => {
  this.setState({ loading: true, error: null });

  const [err, res] = await getRoomMessages(
    this.roomId,
    this.state.pagination.size,
    1,
  );

  if (res) {
    this.setState({
      messages: res.data.reverse(),
      pagination: {
        ...this.state.pagination,
        current: 2,
      },
      noMoreLoad: res.paging.total_page <= 1 ? true : false,
      loading: false,
    });
    this.scrollToBottom();
    await this.readMessage(res.data.pop().id);
  } else {
    this.setState({ error: errorToString(err), loading: false });
  }
};

问题原因

  1. 控制台显示异常:浏览器控制台打印数组/对象时采用的是引用式快照——打印瞬间显示的是元素数量的即时值,但展开时会读取内存中数组的最新状态。你看到展开后少一个元素,是因为后续代码修改了这个数组。
  2. 数组被修改的根源:fetchMessages中调用了res.data.pop(),pop()是会直接修改原数组的方法,会删除数组最后一个元素;同时res.data.reverse()同样会直接反转原数组,这两个操作都改变了response.data.data的原始引用,导致控制台展开时数组状态已变化。
  3. 顺序异常:reverse()修改原数组的操作,直接改变了数组元素的原始顺序,所以单独打印索引时会出现顺序和预期不符的情况。

解决方法

核心是避免直接修改原数组,通过创建数组副本来进行操作:

修改后的fetchMessages代码

fetchMessages = async () => {
  this.setState({ loading: true, error: null });

  const [err, res] = await getRoomMessages(
    this.roomId,
    this.state.pagination.size,
    1,
  );

  if (res) {
    // 创建数组副本再反转,不修改原数组
    const reversedMessages = [...res.data].reverse();
    this.setState({
      messages: reversedMessages,
      pagination: {
        ...this.state.pagination,
        current: 2,
      },
      noMoreLoad: res.paging.total_page <= 1 ? true : false,
      loading: false,
    });
    this.scrollToBottom();
    // 直接读取最后一个元素ID,不删除原数组元素
    await this.readMessage(res.data[res.data.length - 1].id);
  } else {
    this.setState({ error: errorToString(err), loading: false });
  }
};

额外建议

如果需要对返回的数组进行多次操作,建议先创建完整副本:const messagesCopy = [...res.data],后续所有操作都基于这个副本,彻底避免意外修改原数据导致的异常。


内容的提问来源于stack exchange,提问作者Kevin Jayden Wivano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 23:18:33