我需要制作将在点击时过滤的产品列表。但我只是无法掌握如何在反应中做到这一点。主要是:
我敢肯定,对于经验丰富的开发人员来说,这是一个非常微不足道的案例。
到目前为止我的代码的存储库:https://github.com/SolidMike/react-hotels/tree/main/src/
至于现在我有输出我的json的组件 和包含所有过滤器的组件。遗憾的是,我无法理解如何让它与我的动作和减速器一起工作:(
这是我的过滤器
const mapStateToProps = (state) => {
return {
filter: state.filter,
}
}
const mapDispatchToProps = { filtersApply, filtersReset }
function Filter({ filter, filtersApply, filtersReset }) {
console.log(filter)
const typesOptions = [
{ value: 'appartment', label: 'Апартаменты' },
{ value: 'hotel', label: 'Отель' },
]
const countriesOptions = [
{ value: 'greece', label: 'Греция' },
{ value: 'russian', label: 'Россия' },
{ value: 'ukraine', label: 'Украина' },
]
const [types, setTypes] = useState([])
const [countries, setCountries] = useState([])
const handleOnChangeCountries = (selectedOption) => {
setCountries(selectedOption)
console.log(`Option selected:`, selectedOption)
}
const handleOnChangeTypes = (selectedOption) => {
setTypes(selectedOption)
console.log(`Option selected:`, selectedOption)
}
return (
<div>
<div className="filter__country">
<Select
defaultValue={countries}
onChange={handleOnChangeCountries}
options={countriesOptions}
/>
</div>
<label for="type">
Тип
<Select
defaultValue={types}
options={typesOptions}
onChange={handleOnChangeTypes}
isMulti
/>
</label>
<fieldset>
<legend>Количество звезд</legend>
<label for="one_star">
1 звезда
<input
type="checkbox"
name="rating"
id="one_star"
value="1"
/>
</label>
<label for="two_stars">
2 звезды
<input
type="checkbox"
name="rating"
id="two_stars"
value="2"
/>
</label>
<label for="three_stars">
3 звезды
<input
type="checkbox"
name="rating"
id="three_stars"
value="3"
/>
</label>
<label for="four_stars">
4 звезды
<input
type="checkbox"
name="rating"
id="four_stars"
value="4"
/>
</label>
<label for="five_stars">
5 звезд
<input
type="checkbox"
name="rating"
id="five_stars"
value="5"
/>
</label>
</fieldset>
<button
className="filter__apply"
onClick={() => {
filtersApply({ name: 'countryFilter', value: countries })
}}
>
Применить фильтр
</button>
<button className="filter__reset" onClick={filtersReset}>
Очистить фильтр
</button>
</div>
)
}
export default connect(mapStateToProps, mapDispatchToProps)(Filter)
reducer.js 我是否应该将数组置于初始状态,我不确定。
let initialState = {
hotels: [
{
name: 'Marina Inn',
country: 'Греция',
address: 'Фалираки, Родос, Греция',
stars: 4,
type: 'Отель',
description:
'Этот 4-звездочный отель расположен в центре города. На его территории есть бассейн с террасой и сауна. Из номеров открывается вид на море или на средневековый город.',
services: [
'Пляж',
'Кондиционер',
'Открытый бассейн',
'Бесплатная парковка',
'Бесплатный WiFi',
'Вид на море',
'Бесплатный завтрак',
],
min_price: 2789.0,
currency: 'RUR',
rating: 4.5,
reviews_amount: 18,
last_review:
'Отличное расположение. Вкусный завтрак. Отдыхали с детьми - все понравилось.',
},
{
name: 'Mondrian Suites',
country: 'Греция',
address: 'Фалираки, Родос, Греция',
stars: 5,
type: 'Апартаменты',
description:
'Из окон открывается вид на город.К услугам гостей номера-студио с балконом и чайником в 2,7 км от пляжа.',
services: [
'Пляж',
'Кондиционер',
'Открытый бассейн',
'Платная парковка',
'Бесплатный WiFi',
'Вид на море',
],
min_price: 3245.2,
currency: 'RUR',
rating: 5,
reviews_amount: 4,
last_review:
'Потрясающее место, в номере есть все необходимое. Красивый вид на море.',
},
{
name: 'Sunny Appartments',
country: 'Греция',
address: 'Родос, Родос, Греция',
stars: 2,
type: 'Апартаменты',
description:
'Все номера и апартаменты оборудованы кондиционером и телевизором с плоским экраном. Также в распоряжении гостей тостер и чайник.',
services: [
'Пляж',
'Кондиционер',
'Бесплатная парковка',
'Бесплатный WiFi',
],
min_price: 1153.0,
currency: 'RUR',
rating: 2.4,
reviews_amount: 36,
last_review:
'Бассейн очень маленький. Кормят невкусно. Больше не поедем.',
},
{
name: 'Super All Inclusive Hotel',
country: 'Греция',
address: 'Родос, Родос, Греция',
stars: 4,
type: 'Отель',
description:
'Все номера оснащены телевизором с плоским экраном. Из некоторых номеров открывается вид на море или город.',
services: [
'Пляж',
'Кондиционер',
'Открытый бассейн',
'Бесплатный WiFi',
'Вид на море',
'Бесплатный завтрак',
],
min_price: 3689.0,
currency: 'RUR',
rating: 4.1,
reviews_amount: 14,
last_review:
'Недалёко от пляжа и старого города, вокруг много разных магазинчиков',
},
{
name: 'Adams Hotel',
country: 'Греция',
address: 'Родос, Родос, Греция',
stars: 3,
type: 'Отель',
description:
'Отель расположен всего в 100 метрах от пляжа и в 5-ти минутах ходьбы от исторической части города, недалеко от всех основных достопримечательностей. Из отеля открывается вид на море. К услугам гостей спокойный открытый бассейн.',
services: [
'Пляж',
'Кондиционер',
'Открытый бассейн',
'Бесплатная парковка',
'Бесплатный WiFi',
'Бесплатный завтрак',
],
min_price: 1896.0,
currency: 'RUR',
rating: 0,
reviews_amount: 0,
last_review: '',
},
],
countryFilter: [],
typeFilter: [],
starsFilter: [],
reviewsAmountFilter: null,
}
export const FiltersReducer = (state = initialState, action) => {
switch (action.type) {
case 'FILTER_UPDATE': {
console.log(action.payload)
const { name, value } = action.payload
return { ...state, [name]: value }
}
case 'FILTER_RESET': {
return initialState
}
default:
return initialState
}
}
和我的 actions.js
export const filtersApply = (payload) => ({
type: 'FILTER_UPDATE',
payload,
})
export const filtersReset = () => ({
type: 'FILTER_RESET',
})
答案 0 :(得分:1)
我广泛使用的模式之一,不仅是 redux,是将列表保存在两个状态变量中。第一个是某个标识符映射的所有实体的哈希映射,另一个是标识符列表。例如,您有酒店列表。我会这样做:
let initialState = {
hotels: {
1: {
id: 1,
name: "Marina Inn",
country: "Греция",
address: "Фалираки, Родос, Греция",
stars: 4,
type: "Отель",
description:
"Этот 4-звездочный отель расположен в центре города. На его территории есть бассейн с террасой и сауна. Из номеров открывается вид на море или на средневековый город.",
services: [
"Пляж",
"Кондиционер",
"Открытый бассейн",
"Бесплатная парковка",
"Бесплатный WiFi",
"Вид на море",
"Бесплатный завтрак",
],
min_price: 2789.0,
currency: "RUR",
rating: 4.5,
reviews_amount: 18,
last_review:
"Отличное расположение. Вкусный завтрак. Отдыхали с детьми - все понравилось.",
},
2: {
id: 2,
name: "Mondrian Suites",
country: "Греция",
address: "Фалираки, Родос, Греция",
stars: 5,
type: "Апартаменты",
description:
"Из окон открывается вид на город.К услугам гостей номера-студио с балконом и чайником в 2,7 км от пляжа.",
services: [
"Пляж",
"Кондиционер",
"Открытый бассейн",
"Платная парковка",
"Бесплатный WiFi",
"Вид на море",
],
min_price: 3245.2,
currency: "RUR",
rating: 5,
reviews_amount: 4,
last_review:
"Потрясающее место, в номере есть все необходимое. Красивый вид на море.",
},
3: {
name: "Sunny Appartments",
country: "Греция",
address: "Родос, Родос, Греция",
stars: 2,
type: "Апартаменты",
description:
"Все номера и апартаменты оборудованы кондиционером и телевизором с плоским экраном. Также в распоряжении гостей тостер и чайник.",
services: [
"Пляж",
"Кондиционер",
"Бесплатная парковка",
"Бесплатный WiFi",
],
min_price: 1153.0,
currency: "RUR",
rating: 2.4,
reviews_amount: 36,
last_review:
"Бассейн очень маленький. Кормят невкусно. Больше не поедем.",
},
4: {
name: "Super All Inclusive Hotel",
country: "Греция",
address: "Родос, Родос, Греция",
stars: 4,
type: "Отель",
description:
"Все номера оснащены телевизором с плоским экраном. Из некоторых номеров открывается вид на море или город.",
services: [
"Пляж",
"Кондиционер",
"Открытый бассейн",
"Бесплатный WiFi",
"Вид на море",
"Бесплатный завтрак",
],
min_price: 3689.0,
currency: "RUR",
rating: 4.1,
reviews_amount: 14,
last_review:
"Недалёко от пляжа и старого города, вокруг много разных магазинчиков",
},
5: {
name: "Adams Hotel",
country: "Греция",
address: "Родос, Родос, Греция",
stars: 3,
type: "Отель",
description:
"Отель расположен всего в 100 метрах от пляжа и в 5-ти минутах ходьбы от исторической части города, недалеко от всех основных достопримечательностей. Из отеля открывается вид на море. К услугам гостей спокойный открытый бассейн.",
services: [
"Пляж",
"Кондиционер",
"Открытый бассейн",
"Бесплатная парковка",
"Бесплатный WiFi",
"Бесплатный завтрак",
],
min_price: 1896.0,
currency: "RUR",
rating: 0,
reviews_amount: 0,
last_review: "",
},
},
ids: [1, 2, 3, 4, 5],
countryFilter: [],
typeFilter: [],
starsFilter: [],
reviewsAmountFilter: null,
};
现在,根据各种因素,我可以在 redux 内或在渲染它们的组件中执行过滤和排序。无论如何,我所要做的就是排序 ID 数组,并且我可以保持实际列表不变。例如,我想按星星范围过滤所有内容。 Reducer 可能看起来像这样:
function reducer(state = initialState, event) {
if (event.type === "FILTER_UPDATE") {
// get fresh ids list
let ids = Object.keys(state.hotels);
let filteredAndSortedIds = ids
.filter((id) => {
let hotel = state.hotels[id];
// filter on parameters and return true or false
})
.sort((id1, id2) => {
/* sort */
});
// here you also can set filters and sorts if needed
return { ...state, ids: filteredAndSortedIds };
}
if (event.type === "FILTER_RESET") {
let ids = Object.keys(state.hotels).sort((id1, id2) => {
/* perform default sort to get consistent results */
});
// here you also can set default values for filters and sots
return { ...state, ids };
}
}
当您需要添加另一家酒店时,您可以在 hotels
地图中添加新条目并在 ids
数组中添加新条目。
您也可以不在 redux 中执行此类操作,而是在组件渲染中执行此类操作。在这里你需要小心,这样你就不会渲染你不想渲染的东西。在某些情况下,它会影响性能。
要将过滤器值发送到 redux,您已经拥有了所需的东西。只需扩展对象以包含所有值:dispatch(filterApply({'selectedCountries': countries, 'selectedTypes': types}))
等。由于您将它们全部发送到 redux,您可能希望将它们保持在本地状态而不是保存到 redux 存储中以避免复制和执行同步,但这取决于您。无论哪种情况,您都必须在 onClick 处理程序中将您的状态重置为初始状态,如下所示:
const [types, setTypes] = useState([]);
const [countries, setCountries] = useState([]);
<button
className="filter__reset"
onClick={() => {
filtersReset();
setTypes([]);
setCountries([]);
}}
>
Очистить фильтр
</button>;