Потеря опций выбора раскрывающегося списка при фильтрации с использованием API контекста реакции
Я только начал изучать React 2 недели назад, так что мне все еще трудно понять некоторые концепции. Я перешел от создания CRA к преобразованию его в NextJS и выбрал использование контекстного API с хуками для управления состоянием. Я сейчас работаю над фильтрацией списка статей с помощью раскрывающегося списка. Когда я выбираю определенный тип статьи, список фильтруется правильно, но когда я возвращаюсь к раскрывающемуся списку, там присутствует только исходный вариант вместе с текущим. Когда я нажимаю на исходный вариант, все элементы списка исчезают. Я хочу предотвратить изменение параметров в раскрывающемся списке, а также позволить фильтрации работать одновременно с установкой других фильтров (например, фильтр сортировки по городу И фильтр по функции статьи).
В моем коде я борюсь с тем, чтобы выпадающий список рынков / рынков работал правильно.
Это мой context.js
import React, { useState, useReducer, createContext } from "react";
import { articles } from "./data";
// Create Context Object
const StateContext = React.createContext([{}, () => {}]);
// Create a provider for components to consume and subscribe to changes
const StateProvider = (props) => {
const [state, setState] = useState({
list: articles,
market: "All",
isLoading: true,
});
return (
<StateContext.Provider value={[state, setState]}>
{props.children}
</StateContext.Provider>
);
};
export { StateContext, StateProvider };
FilterControls.js:
import React from "react";
import useFilter from "../hooks/useFilter";
const Controls = () => {
const { allEntries, market, handleChange } = useFilter();
// get all unique values
const getUnique = (items, value) => {
return [...new Set(items.map((item) => item[value]))];
};
let markets = getUnique(allEntries, "market");
// add all
markets = ["All", ...markets];
// map to jsx
markets = markets.map((item, index) => {
return (
<option value={item} key={index}>
{item}
</option>
);
});
return (
<>
<div>
<section className="filter-container">
{/* select market */}
<div className="form-group">
<label htmlFor="market">Housing Market</label>
<select
name="market"
id="market"
value={market}
className="form-control drop-down"
onChange={handleChange}
>
{markets}
</select>
</div>
{/* end of select market */}
</section>
useFilter.js:
import { useContext } from "react";
import { StateContext } from "../context";
const StateFilter = () => {
const [state, setState] = useContext(StateContext);
let allEntries = formatData(state.list);
let featuredEntries = allEntries.filter((e) => e.featured === true);
let percentageOffMax = Math.max(
...allEntries.map((item) => item.percentageOff)
);
let avgppMax = Math.max(...allEntries.map((item) => item.avgpp));
function formatData(items) {
let tempItems = items.map((e) => {
let id = e.id;
let images = e.images;
let singleEntry = { ...e, images, id };
return singleEntry;
});
return tempItems.sort((a, b) => a.avgpp - b.avgpp);
}
function sortFromHighestToLowestPrices(items) {
let tempItems = items.map((e) => {
let id = e.id;
let images = e.images;
let singleEntry = { ...e, images, id };
return singleEntry;
});
return tempItems.sort((a, b) => b.avgpp - a.avgpp);
}
let highestToLowest = sortFromHighestToLowestPrices(state.list);
// console.log(state.market);
// console.log(state);
// console.log(allEntries.filter((e) => e.market === "Homeowners"));
function handleChange(event) {
const target = event.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = event.target.name;
console.log(value);
let ftest = allEntries.filter((e) => e.market === value);
setState((state) => ({ ...state, list: ftest, [name]: value }));
// state.filterItems();
// setState((state) =>({...state.market}))
// {
// [name]: value,
// },
// this.filterItems
// );
console.log(state);
}
// allEntries.filter((e) => e.market === value);
function filterItems() {
console.log(state.list);
let { allEntries } = state.list;
// let tempEntries = [...allEntries].sort((a, b) => b.avgpp - a.avgpp);
// if (market !== "All") {
// tempEntries = tempEntries.filter((e) => e.market === market);
// }
}
console.log(filterItems());
return {
isLoading: state.isLoading,
allEntries,
featuredEntries,
sortedEntries: allEntries,
percentageOff: percentageOffMax,
percentageOffMax,
avgppMax,
handleChange,
filterItems,
};
};
export default StateFilter;
И article.js, где все отображается:
import React, { useContext } from "react";
import Entry from "../components/Entry";
import Title from "../components/Title";
import { StateContext } from "../context";
import FilterControls from "../components/FilterControls";
import useFilter from "../hooks/useFilter";
const FullList = () => {
const { allEntries, showAdelphi, isLoading } = useFilter();
return (
<>
<section className="all-entries">
<Title title="Featured Entries" />
<FilterControls />
<div className="all-entries-center">
{allEntries.map((e) => (
<Entry key={e.id} entry={e} />
))}
</div>
</section>
1 ответ
Причина, по которой это не сработало, заключалась в том, что не был создан временный список. Следовательно, когда был выбран элемент опции, состояние заменялось тем, в котором не было другого элемента (ов). Поскольку раскрывающийся список является источником состояния, параметры исчезают, поскольку количество элементов в исходном списке уменьшается.
Чтобы решить эту проблему, я вместо этого создал временный список, который будет корректироваться на основе установленных фильтров, при этом исходный список будет сохранен для справки.
Отсортированный список теперь является тем, который отображает список на странице моих статей:
<section className="all-entries">
<Title title="Featured Entries" />
<FilterControls />
<div className="all-entries-center">
{state.sortedList.map((e) => (
<Entry key={e.id} entry={e} />
))}
</div>
</section>
И теперь, в моем фильтре, рынки взяты из исходного списка:
let markets = getUnique(list, "market");
// add all
markets = ["All", ...markets];
// map to jsx
markets = markets.map((item, index) => {
return (
<option value={item} key={index}>
{item}
</option>
);
});