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

React组件排序后渲染数据未按顺序展示问题排查

为什么渲染的数据没有按照排序顺序展示

问题根本不是排序逻辑执行完成前触发了渲染,是代码存在3个核心逻辑错误,导致排序时拿到的数据本身不完整,且计算完成后没有触发视图更新:

  • 距离计算逻辑没有等待异步任务完成,也没有触发状态更新
    你在父组件的updaterides函数里用rides.map执行异步的距离计算,但没有用Promise.all等待所有计算任务执行完。同时你是直接给原状态里的ride对象挂载distance属性,全程没有调用setRides更新状态,React完全感知不到rides数据的变化,传给子组件的props不会触发子组件重新执行排序逻辑。
  • 排序逻辑的await无实际作用
    Array.sort()是同步执行的方法,不会返回Promise,在它前面加await没有任何等待效果。子组件的排序effect第一次执行时,拿到的还是接口返回的原始rides数据,所有ride的distance字段都是undefined,此时比较排序的结果完全随机,不符合预期。
  • 原地排序存在副作用
    sort()方法会直接修改原数组,你直接对props传入的rides调用sort,会直接修改父组件的状态对象,违反React单向数据流原则,容易引发不可预期的渲染问题。

修复方案

1. 修改父组件Rides.js

核心调整:等待所有距离计算完成后,再调用setRides更新状态,不要直接修改原状态对象:

import { useEffect, useState } from "react";
import Navbar from "./Navbar";
import NearestRides from "./NearestRides";

const Rides = () => {
  const [rides, setRides] = useState([]);
  const [user, setUser] = useState({});


  useEffect(() => {
    const fetchRides = async () => {
      const data = await fetch('https://assessment.api.vweb.app/rides');
      const json = await data.json();
      setRides(json);
    }

    const fetchUser = async () => {
      const data = await fetch('https://assessment.api.vweb.app/user');
      const json = await data.json();
      console.log(json);
      setUser(json);
    }
    
    const makeNetworkCalls = async() => {
      await fetchRides();
      await fetchUser();
    }

    makeNetworkCalls().catch((e) => {
      console.log(e);
    })

  }, [])

  useEffect(() => {
    // 距离计算是纯同步逻辑,不需要加async
    const calculateDistance = (path, user_station) => {
      let min = Math.abs(user_station - path[0]);
      for(let i = 0; i<path.length; i++){
        if(path[i] === user_station){
          return 0;
        }
        if(Math.abs(path[i] - user_station) < min){
          min = Math.abs(path[i] - user_station);
        }
      }
      return min;
    }

    const updaterides = async () => {
      // 等待所有距离计算完成,新建对象避免直接修改原状态
      const updatedRides = await Promise.all(
        rides.map(async (ride) => {
          const distance = calculateDistance(
            ride.station_path,
            user.station_code
          );
          return {...ride, distance}
        })
      )
      // 计算完成后更新状态,触发子组件重渲染
      setRides(updatedRides);
    };

    if (rides?.length > 0 && user.station_code) {
      updaterides().catch((e) => {
        console.log(e);
      });
    }
  }, [rides,user]);

  return (
    <div>
      <Navbar user = {user}/>
      <div className="home">
        <NearestRides rides = {rides}/>
      </div>
    </div>
  );

}

export default Rides;

2. 修改子组件NearestRides.js

核心调整:去掉无意义的await,排序前先浅拷贝数组避免修改原props,等rides的distance字段都计算完成后再执行排序:

import { useEffect, useState } from "react";

const NearestRides = ({rides}) => {
  const [sortedRides, setSortedRides] = useState([]);

  useEffect(() => {
    // 所有ride都有distance字段时再排序,避免比较undefined
    const hasAllDistance = rides.length > 0 && rides.every(ride => typeof ride.distance === 'number');
    if (!hasAllDistance) return;

    // 先浅拷贝数组再排序,避免修改原props数组
    const sorted = [...rides].sort((ride1,ride2) => {
      // 数字排序直接用差值比较,比大小判断更简洁准确
      return ride1.distance - ride2.distance;
    })
    setSortedRides(sorted);

  }, [rides]);

  return(
    <div className="rides">
      {sortedRides?.map((ride) => {
        return (
          // 列表项必须加唯一key,避免diff出错
          <div className="ride-detail" key={ride.id}>
          <img src={ride.map_url} alt="Ride_map" />
          <div>
            <p>Ride Id : {ride.id}</p>
            <p>Origin Station : {ride.origin_station_code}</p>
            <p>Station Path : {ride.station_path}</p>
            <p>Date : {ride.date}</p>
            <p>Distance : {ride.distance}</p>
          </div>
        </div>
        )
      })}
    </div>
  )
}

export default NearestRides;

内容的提问来源于stack exchange,提问作者Anuj kumar Jaimini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:01:04