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

React中useEffect渲染异常:移除tempFlights状态的优化方案

问题原因分析
  1. 数组引用类型导致原数组被修改:JavaScript中数组是引用类型,flights.sort()是原地排序方法——它会直接修改调用它的原数组(也就是useFetchFlightResults返回的flights),而非返回新数组。所以不管你是否将排序结果赋值给temp,原flights的顺序已经被改变。
  2. setTempFlights触发重渲染同步显示变化:执行setTempFlights([...temp])时会触发组件重渲染,此时flights已经被之前的sort修改,页面基于flights渲染时就能立刻看到排序后的结果。
  3. 移除setTempFlights后的延迟问题:去掉setTempFlights后,useEffect里的flights.sort()仍会修改原数组,但useEffect是在组件渲染完成后执行的——这次修改不会触发组件重渲染,页面还是显示排序前的flights,直到下次用户修改sortBy触发组件重新渲染,才会用上已经被修改过的flights,因此出现“需等待用户下次输入才更新”的情况。
移除tempFlights的实现方案

核心思路是不修改原flights数组,通过衍生值或状态管理排序结果,以下是两种可行方案:

方案一:使用useMemo计算排序后的数组(推荐)

利用useMemo缓存排序结果,仅在flights或sortBy变化时重新计算,避免不必要的性能消耗:

import React, { useState, useMemo } from "react";
import "./index.style.css";
import FlightSearchItem from "./FlightSearchItem";
import FlightSearchFooter from "./FlightSearchFooter";
import useFetchFlightResults from "./useFetchFlightResults";
import SortBy from "./filters/SortBy";
import { SortByDefaultOption } from "./filters/SortBy/enums";

export default function FlightSearch() {
  const [sortBy, setSortBy] = useState(SortByDefaultOption);
  const { flights } = useFetchFlightResults();

  // 缓存排序后的数组,先拷贝原数组避免修改原数据
  const sortedFlights = useMemo(() => {
    const flightsCopy = [...flights];
    if (sortBy.value === "PRICE_LOW") {
      return flightsCopy.sort((a, b) => a.price - b.price);
    } else if (sortBy.value === "BEST") {
      return flightsCopy.sort((a, b) => a.score - b.score);
    } else {
      return flightsCopy.sort((a, b) => {
        return new Date(a.segmentsArray[0].arrivesAt) - new Date(b.segmentsArray[0].arrivesAt);
      });
    }
  }, [flights, sortBy]);

  // 基于排序后的数组做分页
  const paginatedFlights = sortedFlights.slice(0, 8);

  return (
    <div className="row">
      <div className="pane m-t-1">
        <div className="pane-header search-results__header">
          <div className="search-results__title">
            <b>Select an outbound flight</b>
            <p className="m-v-0 fade small">DEN → CHI</p>
          </div>
          <SortBy value={sortBy} onChange={setSortBy} />
        </div>
        <div className="pane-content">
          {Array.isArray(paginatedFlights) &&
            paginatedFlights.map((flight) => (
              <FlightSearchItem key={flight.id} flight={flight} />
            ))}
        </div>
      </div>
      <FlightSearchFooter />
    </div>
  );
}

方案二:使用状态存储排序后的数组

如果需要后续手动修改排序结果,可使用useState存储排序后的数组,在useEffect中更新:

import React, { useEffect, useState } from "react";
import "./index.style.css";
import FlightSearchItem from "./FlightSearchItem";
import FlightSearchFooter from "./FlightSearchFooter";
import useFetchFlightResults from "./useFetchFlightResults";
import SortBy from "./filters/SortBy";
import { SortByDefaultOption } from "./filters/SortBy/enums";

export default function FlightSearch() {
  const [sortBy, setSortBy] = useState(SortByDefaultOption);
  const { flights } = useFetchFlightResults();
  const [sortedFlights, setSortedFlights] = useState([...flights]);

  useEffect(() => {
    const flightsCopy = [...flights];
    let sorted = [];
    if (sortBy.value === "PRICE_LOW") {
      sorted = flightsCopy.sort((a, b) => a.price - b.price);
    } else if (sortBy.value === "BEST") {
      sorted = flightsCopy.sort((a, b) => a.score - b.score);
    } else {
      sorted = flightsCopy.sort((a, b) => {
        return new Date(a.segmentsArray[0].arrivesAt) - new Date(b.segmentsArray[0].arrivesAt);
      });
    }
    setSortedFlights(sorted);
  }, [flights, sortBy]);

  const paginatedFlights = sortedFlights.slice(0, 8);

  return (
    <div className="row">
      <div className="pane m-t-1">
        <div className="pane-header search-results__header">
          <div className="search-results__title">
            <b>Select an outbound flight</b>
            <p className="m-v-0 fade small">DEN → CHI</p>
          </div>
          <SortBy value={sortBy} onChange={setSortBy} />
        </div>
        <div className="pane-content">
          {Array.isArray(paginatedFlights) &&
            paginatedFlights.map((flight) => (
              <FlightSearchItem key={flight.id} flight={flight} />
            ))}
        </div>
      </div>
      <FlightSearchFooter />
    </div>
  );
}

关键注意点

  • 禁止直接修改useFetchFlightResults返回的flights数组,这属于外部状态,直接修改会导致状态不一致,引发难以排查的bug。
  • 排序前必须先拷贝原数组(用[...flights]或flights.slice()),确保原数组不受影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 15:18:13