用React过滤无法正常工作
每当我的3个过滤器中的任何一个都更改时,我都在尝试过滤一系列汽车。我认为合适的方式 - 对于瞬间的瞬间 - 每当任何一个更改时,请检查所有过滤器,按以下顺序:handle onchangeDateFilter(如果未设置此过滤器,我将所有汽车都设置为初始状态),thangeonchangefuelfter, hangeonchangeseats。我显示了一些console.log
s,但出于某种原因(我认为它可能与渲染相关,并且 使用使用。或在依赖项数组中的任何值更改后,对吗?)(PS:我知道我可以以某种方式通过以某种方式捕获Prevstate,以某种方式检查新值与旧值,以便我不运行一个没有理由再次过滤器,但是忘记了如何捕获Prevstate,因为它也应该可以正常工作,因为现在也应该很好地捕获Prevstate),
因此,任何想法以下代码为什么不起作用?
import moment from "moment";
import { Link } from "react-router-dom";
import Spinner from "../components/Spinner";
import { Col, Row, DatePicker, Select } from "antd";
import React, { useState, useEffect, useRef } from "react";
import { useSelector, useDispatch } from "react-redux";
import DefaultLayout from "../components/DefaultLayout";
import { getAllCars } from "../redux/actions/carsActions";
import cron from "node-cron";
const { RangePicker } = DatePicker;
function Home() {
const { cars } = useSelector((state) => state.carsReducer); // state aici e de fapt store-ul nostru!
const [timeRange, setTimeRange] = useState([]);
const [fuelTypes, setFuelTypes] = useState([]);
const [seatNumbers, setSeatNumbers] = useState([]);
const { loading } = useSelector((state) => state.alertsReducer);
const [totalCars, setTotalcars] = useState([]);
const dispatch = useDispatch();
useEffect(() => {
console.log("merge!");
dispatch(getAllCars());
}, []);
useEffect(() => {
console.log("cars bro", cars);
setFuelTypes(
[...new Set(cars.map((car) => car.fuelType.toLowerCase()))].sort()
);
setSeatNumbers(
[...new Set(cars.map((car) => car.capacity))].sort((a, b) => a - b)
);
setTotalcars(cars);
}, [cars]);
useEffect(() => {
console.log("refilter is triggered!");
refilter();
}, [timeRange, fuelTypes, seatNumbers]);
function handleOnChangeDateFilter() {
console.log("intra in handleOnChangeDateFilter", timeRange);
console.log("totalCars:", totalCars);
if (timeRange.length === 0) {
console.log(
"No date range filter specified! Will reinitialize and then proceed with other filters!"
);
setTotalcars(cars);
return;
}
var selectedFrom = moment(timeRange[0], "MMM DD yyyy HH:mm");
var selectedTo = moment(timeRange[1], "MMM DD yyyy HH:mm");
console.log("selectedFrom", selectedFrom, "selectedTo", selectedTo);
var temp = [];
for (var car of cars) {
if (car.bookedTimeSlots.length === 0) {
temp.push(car);
} else {
var toAdd = true;
for (var booking of car.bookedTimeSlots) {
if (
selectedFrom.isBetween(booking.from, booking.to) ||
selectedTo.isBetween(booking.from, booking.to) ||
moment(booking.from).isBetween(selectedFrom, selectedTo) ||
moment(booking.to).isBetween(selectedFrom, selectedTo)
) {
console.log(
`${car.name} is booked from ${booking.from} to ${booking.to}! Will NOT be added!`
);
toAdd = false;
break; // we should not add this car to the displayed cars if we found a minimum of one booking that
// intersects non-available time range
}
}
if (toAdd) temp.push(car);
}
}
setTotalcars(temp);
}
function handleOnChangeFuelFilter() {
console.log(`intra in handleOnChangeFuelFilter:`, totalCars);
if (fuelTypes === []) {
console.log("no fuel filter specified! Will leave function!");
return;
}
var temp = [];
for (var car of totalCars) {
if (fuelTypes.includes(car.fuelType.toLowerCase())) {
// console.log(`${car.name} is of type ${car.fuelType}! Will be added!`);
temp.push(car);
}
}
setTotalcars(temp);
}
function handleOnChangeSeatsFilter() {
console.log(`intra in handleOnChangeSeatsFilter:`, totalCars);
if (seatNumbers === []) {
console.log("No seat filter specified! Will leave function!");
return;
}
var temp = [];
for (var car of totalCars) {
if (seatNumbers.includes(car.capacity)) {
// console.log(`${car.name} has ${car.capacity}! Will be added!`);
temp.push(car);
}
}
setTotalcars(temp);
}
function onRangePickerFilterChange(values) {
console.log("============STARTED============");
console.log("onRangePickerFilterChange ->", values);
setTimeRange(values);
}
function onSeatsFilterChange(values) {
console.log("============STARTED============");
console.log("onSeatsFilterChange ->", values);
setSeatNumbers(values);
}
function onFuelFilterChange(values) {
console.log("============STARTED============");
console.log("onFuelFilterChange ->", values);
setFuelTypes(values);
}
function refilter() {
// console.log('values refilter:', values);
// console.log('============STARTED============');
handleOnChangeDateFilter();
console.log("AFTER DATE FILTER:", totalCars);
handleOnChangeFuelFilter();
console.log("AFTER FUEL FILTER:", totalCars);
handleOnChangeSeatsFilter();
console.log("AFTER SEATS FILTER(final):", totalCars);
console.log("============FINISHED============");
}
return (
<DefaultLayout>
<Row className="mt-3" justify="center">
<Col lg={20} sm={24} className="d-flex justify-content-left">
<RangePicker
// ref={refRangePicker}
showTime={{ format: "HH:mm" }}
format="MMM DD yyyy HH:mm"
// onChange={handleOnChangeDateFilter}
// onChange={refilter}
onChange={onRangePickerFilterChange}
/>
<Select
// onChange={handleFuelFilterChange}
// onChange={refilter}
onChange={onFuelFilterChange}
allowClear
mode="multiple"
placeholder="Fuel type"
style={{ width: "10%" }}
>
{fuelTypes.map((fuelType, index) => {
return (
<Select.Option key={index} value={fuelType}>
{fuelType}
</Select.Option>
);
})}
</Select>
<Select
// onChange={refilter}
onChange={onSeatsFilterChange}
allowClear
mode="multiple"
placeholder="Seats"
style={{ width: "10%" }}
>
{seatNumbers.map((seatNumber, index) => {
return (
<Select.Option key={index} value={seatNumber}>
{seatNumber}
</Select.Option>
);
})}
</Select>
</Col>
</Row>
{loading === true && <Spinner />}
<Row justify="center" gutter={16}>
{totalCars.map((car) => {
return (
<Col lg={5} sm={24} xs={24}>
<div className="car p-1 bs1">
<img src={car.image} className="carimg" />
<div className="car-content d-flex align-items-center justify-content-between">
<div className="text-left pl-2">
<p>{car.name}</p>
<p>
<sup>{car.rentPerHour} eur</sup>/<sub>Hour</sub>
</p>
</div>
<div className="text-left pl-2">
<p>Seats: {car.capacity}</p>
</div>
<div className="text-left pl-2">
<p>Fuel: {car.fuelType}</p>
</div>
<div>
<button className="btn1 mr-2">
<Link to={`/booking/${car._id}`}>Book Now</Link>
</button>
</div>
</div>
</div>
</Col>
);
})}
</Row>
</DefaultLayout>
);
}
export default Home;
I am trying to filter an array of cars whenever any of my 3 filters changes. The way I see fit -for the moment- with React is to: check all filters whenever any of them changes, in this order: handleOnChangeDateFilter (where I set all my cars to the initial state if this filter is not set), handleOnChangeFuelFilter, handleOnChangeSeats. I displayed some console.log
s but for some reason (I think it might be something related to rendering and when useEffect runs. It runs after every re-render OR after any of the values in the dependency array changes, right?) (PS: I know I could somehow check to compare the new values with the old values by somehow capturing the prevState, so that I do not run a specific filter again with no reason, but forgot how to capture prevState. Will do that later, as it should work fine without that now, too)
So, any idea why the below code does not work?
import moment from "moment";
import { Link } from "react-router-dom";
import Spinner from "../components/Spinner";
import { Col, Row, DatePicker, Select } from "antd";
import React, { useState, useEffect, useRef } from "react";
import { useSelector, useDispatch } from "react-redux";
import DefaultLayout from "../components/DefaultLayout";
import { getAllCars } from "../redux/actions/carsActions";
import cron from "node-cron";
const { RangePicker } = DatePicker;
function Home() {
const { cars } = useSelector((state) => state.carsReducer); // state aici e de fapt store-ul nostru!
const [timeRange, setTimeRange] = useState([]);
const [fuelTypes, setFuelTypes] = useState([]);
const [seatNumbers, setSeatNumbers] = useState([]);
const { loading } = useSelector((state) => state.alertsReducer);
const [totalCars, setTotalcars] = useState([]);
const dispatch = useDispatch();
useEffect(() => {
console.log("merge!");
dispatch(getAllCars());
}, []);
useEffect(() => {
console.log("cars bro", cars);
setFuelTypes(
[...new Set(cars.map((car) => car.fuelType.toLowerCase()))].sort()
);
setSeatNumbers(
[...new Set(cars.map((car) => car.capacity))].sort((a, b) => a - b)
);
setTotalcars(cars);
}, [cars]);
useEffect(() => {
console.log("refilter is triggered!");
refilter();
}, [timeRange, fuelTypes, seatNumbers]);
function handleOnChangeDateFilter() {
console.log("intra in handleOnChangeDateFilter", timeRange);
console.log("totalCars:", totalCars);
if (timeRange.length === 0) {
console.log(
"No date range filter specified! Will reinitialize and then proceed with other filters!"
);
setTotalcars(cars);
return;
}
var selectedFrom = moment(timeRange[0], "MMM DD yyyy HH:mm");
var selectedTo = moment(timeRange[1], "MMM DD yyyy HH:mm");
console.log("selectedFrom", selectedFrom, "selectedTo", selectedTo);
var temp = [];
for (var car of cars) {
if (car.bookedTimeSlots.length === 0) {
temp.push(car);
} else {
var toAdd = true;
for (var booking of car.bookedTimeSlots) {
if (
selectedFrom.isBetween(booking.from, booking.to) ||
selectedTo.isBetween(booking.from, booking.to) ||
moment(booking.from).isBetween(selectedFrom, selectedTo) ||
moment(booking.to).isBetween(selectedFrom, selectedTo)
) {
console.log(
`${car.name} is booked from ${booking.from} to ${booking.to}! Will NOT be added!`
);
toAdd = false;
break; // we should not add this car to the displayed cars if we found a minimum of one booking that
// intersects non-available time range
}
}
if (toAdd) temp.push(car);
}
}
setTotalcars(temp);
}
function handleOnChangeFuelFilter() {
console.log(`intra in handleOnChangeFuelFilter:`, totalCars);
if (fuelTypes === []) {
console.log("no fuel filter specified! Will leave function!");
return;
}
var temp = [];
for (var car of totalCars) {
if (fuelTypes.includes(car.fuelType.toLowerCase())) {
// console.log(`${car.name} is of type ${car.fuelType}! Will be added!`);
temp.push(car);
}
}
setTotalcars(temp);
}
function handleOnChangeSeatsFilter() {
console.log(`intra in handleOnChangeSeatsFilter:`, totalCars);
if (seatNumbers === []) {
console.log("No seat filter specified! Will leave function!");
return;
}
var temp = [];
for (var car of totalCars) {
if (seatNumbers.includes(car.capacity)) {
// console.log(`${car.name} has ${car.capacity}! Will be added!`);
temp.push(car);
}
}
setTotalcars(temp);
}
function onRangePickerFilterChange(values) {
console.log("============STARTED============");
console.log("onRangePickerFilterChange ->", values);
setTimeRange(values);
}
function onSeatsFilterChange(values) {
console.log("============STARTED============");
console.log("onSeatsFilterChange ->", values);
setSeatNumbers(values);
}
function onFuelFilterChange(values) {
console.log("============STARTED============");
console.log("onFuelFilterChange ->", values);
setFuelTypes(values);
}
function refilter() {
// console.log('values refilter:', values);
// console.log('============STARTED============');
handleOnChangeDateFilter();
console.log("AFTER DATE FILTER:", totalCars);
handleOnChangeFuelFilter();
console.log("AFTER FUEL FILTER:", totalCars);
handleOnChangeSeatsFilter();
console.log("AFTER SEATS FILTER(final):", totalCars);
console.log("============FINISHED============");
}
return (
<DefaultLayout>
<Row className="mt-3" justify="center">
<Col lg={20} sm={24} className="d-flex justify-content-left">
<RangePicker
// ref={refRangePicker}
showTime={{ format: "HH:mm" }}
format="MMM DD yyyy HH:mm"
// onChange={handleOnChangeDateFilter}
// onChange={refilter}
onChange={onRangePickerFilterChange}
/>
<Select
// onChange={handleFuelFilterChange}
// onChange={refilter}
onChange={onFuelFilterChange}
allowClear
mode="multiple"
placeholder="Fuel type"
style={{ width: "10%" }}
>
{fuelTypes.map((fuelType, index) => {
return (
<Select.Option key={index} value={fuelType}>
{fuelType}
</Select.Option>
);
})}
</Select>
<Select
// onChange={refilter}
onChange={onSeatsFilterChange}
allowClear
mode="multiple"
placeholder="Seats"
style={{ width: "10%" }}
>
{seatNumbers.map((seatNumber, index) => {
return (
<Select.Option key={index} value={seatNumber}>
{seatNumber}
</Select.Option>
);
})}
</Select>
</Col>
</Row>
{loading === true && <Spinner />}
<Row justify="center" gutter={16}>
{totalCars.map((car) => {
return (
<Col lg={5} sm={24} xs={24}>
<div className="car p-1 bs1">
<img src={car.image} className="carimg" />
<div className="car-content d-flex align-items-center justify-content-between">
<div className="text-left pl-2">
<p>{car.name}</p>
<p>
<sup>{car.rentPerHour} eur</sup>/<sub>Hour</sub>
</p>
</div>
<div className="text-left pl-2">
<p>Seats: {car.capacity}</p>
</div>
<div className="text-left pl-2">
<p>Fuel: {car.fuelType}</p>
</div>
<div>
<button className="btn1 mr-2">
<Link to={`/booking/${car._id}`}>Book Now</Link>
</button>
</div>
</div>
</div>
</Col>
);
})}
</Row>
</DefaultLayout>
);
}
export default Home;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题在于过滤逻辑,而不是使用效率或与反应严格相关的其他任何内容。这是完整的工作代码(可以改进,但这是一个工作解决方案):
The problem was with the filtering logic, not the useEffects or anything else strictly related to React. Here is the full working code (could be improved, but this is a working solution):