I am building an application that has a database of videos that can be filtered by category and sorted by rating.
Filtering works after changing the options. However, when I change the categories of the video the filtering does not start automatically. I added useEffect but I don't know what else I can change and why it happens. Please help how to make the sorting not disappear when changing the cateogry.
UPDATE:
import * as _ from "lodash";
import { useEffect, useState } from "react";
import { getAllPrograms } from "../../helpers/getData";
import { TVProgram } from "../../models/models";
import Filters from "../Filters/Filters";
import ProgramsList from "../ProgramsList/ProgramsList";
import Sorting from "../Sorting/Sorting";
import "./HomePage.scss";
const HomePage = () => {
const [programs, setPrograms] = useState<Array<TVProgram>>([]);
const [category, setCategory] = useState<string>("movie,series");
const [sortedPrograms, setSortedPrograms] = useState<TVProgram[]>(programs);
const getPrograms = async (category: string) => {
const programs = await getAllPrograms(category);
setPrograms(programs);
};
useEffect(() => {
getPrograms(category);
}, [category]);
const updateCategory = (categoryName: string): void => {
setCategory(categoryName);
console.log("catName", categoryName);
};
const updatePrograms = (sortedPrograms: TVProgram[]): void => {
setSortedPrograms(sortedPrograms);
console.log("sortedPrograms", sortedPrograms);
};
return (
<div className="container">
<div>
<Filters
updateCategory={updateCategory}
currentCategory={category}
></Filters>
<Sorting programs={programs} setPrograms={updatePrograms}></Sorting>
</div>
<ProgramsList programs={sortedPrograms}></ProgramsList>
</div>
);
};
export default HomePage;
import _ from "lodash";
import { ChangeEvent, useEffect, useState } from "react";
import { sortProgramsByOrder } from "../../helpers/helpers";
import { TVProgram } from "../../models/models";
import "./Sorting.scss";
interface SortingListProps {
programs: TVProgram[];
setPrograms: (programs: TVProgram[]) => void;
}
const Sorting = ({ programs, setPrograms }: SortingListProps) => {
const OPTIONS = ["imdb rating descending", "imdb rating ascending"];
const [selectedOption, setSelectedOption] = useState<string>("");
const [sortedPrograms, setSortedPrograms] = useState<TVProgram[]>([]);
useEffect(() => {
if (selectedOption === OPTIONS[0]) {
setSortedPrograms(sortProgramsByOrder(programs, "desc"));
} else if (selectedOption === OPTIONS[1]) {
setSortedPrograms(sortProgramsByOrder(programs, "asc"));
}
}, [selectedOption, programs]);
const handleChange = (event: ChangeEvent<HTMLSelectElement>) => {
console.log();
setSelectedOption(event.target.value);
setPrograms(sortedPrograms);
};
return (
<div>
<select value={selectedOption} onChange={handleChange}>
<option selected>Sortuj</option>
{OPTIONS.map((option) => (
<option
key={option}
value={option}
selected={option === selectedOption}
>
{option}
</option>
))}
</select>
</div>
);
};
export default Sorting;
CodePudding user response:
useEffect()
is a hook that prevents updates to a variable except in specific cases. Any variable passed into the array at the end of the useEffect()
hook will cause the code inside to be run again when its value changes. The problem looks, at first glance, to be in the following part of your code:
useEffect(() => {
if (selectedOption === OPTIONS[0]) {
sortPrograms(sortProgramsByOrder(programs, "desc"));
} else if (selectedOption === OPTIONS[1]) {
sortPrograms(sortProgramsByOrder(programs, "asc"));
}
}, [selectedOption]);
The [selectedOption]
is telling the hook to only do the sorting if the sorting order has changed. However, you want to call this hook if the order or the contents changes. As such, you want to replace this array with [selectedOption, programs]
so that changes to the contents of the programs variable will also lead to the sorting being re-run.
If programs
is updated in the hook and also set by the hook, this leads to a recursive call which is not good. Instead, let's change the displayed value to be a new variable (defined with useState) called sortedPrograms
. Then your hook should look like this:
useEffect(() => {
if (selectedOption === OPTIONS[0]) {
setSortedPrograms(sortProgramsByOrder(programs, "desc"));
} else if (selectedOption === OPTIONS[1]) {
setSortedPrograms(sortProgramsByOrder(programs, "asc"));
}
}, [selectedOption, programs]);