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
相关产品推荐
相关产品推荐

