In my useEffect, I sort an array based on a users input.
I created an extra useState const [tempFlights, setTempFlights] = React.useState([]);
that I only use in my UseEffect. This is a .js file not a .jsx file (I am working on another persons code base).
In my useEffect I update setTempFlights
and my date for flights
updates, when I remove the update for setTempFlights
, flights
isn't update until the next time the user chooses an input.
Here is my code
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);
// Fetch Flights
const { flights } = useFetchFlightResults();
const [tempFlights, setTempFlights] = React.useState([]);
useEffect(() => {
let temp = [];
if (sortBy.value === "PRICE_LOW") {
temp = flights.sort((a, b) => a.price - b.price);
setTempFlights([...temp]);
} else if (sortBy.value === "BEST") {
temp = flights.sort((a, b) => a.score - b.score);
setTempFlights([...temp]);
} else {
temp = flights.sort((a, b) => {
return (
new Date(a.segmentsArray[0].arrivesAt) -
new Date(b.segmentsArray[0].arrivesAt)
);
});
setTempFlights([...temp]);
}
}, [sortBy]);
// Only show 10 flight results per page
let paginatedFlights = flights.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>
{/* Display Flight Results */}
<div className="pane-content">
{Array.isArray(paginatedFlights) &&
paginatedFlights.map((flight) => (
<FlightSearchItem key={flight.id} flight={flight} />
))}
</div>
</div>
{/* Pagination */}
<FlightSearchFooter />
</div>
);
}
You can see that the page updates based off of flights not tempFlights.
What is going on here and how can I change it to not need setTempFlights([...temp]);
.sort()
mutates the original array (flights in this case). This is why you are seeing updates even though you aren't using tempFlights
. Oftentimes when using sort
, you would create a copy of the original array beforehand to avoid mutating it.
const tempFlights = [...flights];
tempFlights.sort()
In the above, tempFlights
ends up sorted and flights
is left alone.
If I were rewriting your snippet, I wouldn't use an effect at all. The resulting array can easily be derived from the selected sort value and doesn't need to be held in state separately.
const [sortBy, setSortBy] = useState(SortByDefaultOption);
// Fetch Flights
const { flights } = useFetchFlightResults();
const getTempFlights = () => {
let temp = [...flights];
if (sortBy.value === "PRICE_LOW") {
temp.sort((a, b) => a.price - b.price);
} else if (sortBy.value === "BEST") {
temp.sort((a, b) => a.score - b.score);
} else {
temp.sort((a, b) => {
return (
new Date(a.segmentsArray[0].arrivesAt) -
new Date(b.segmentsArray[0].arrivesAt)
);
});
}
return temp;
}
const tempFlights = getTempFlights();
// Render logic as before
You could wrap getTempFlights
in a useMemo hook if you're worried about recalculating the array each render, but it is often not consequential with typical data sets