用反应进行多过滤无法正常工作

发布于 2025-01-31 05:18:28 字数 3488 浏览 3 评论 0原文

每当我的两个过滤器中的任何一个都会更改时,我都在尝试过滤一系列汽车。我运行自己的灌输功能,在其中检查所有过滤器(不仅是更改的过滤器),如下所示。知道为什么它不起作用吗?我希望每当我单击过滤器或所有汽车时,如果没有使用过滤器,就会看到汽车满足过滤器。当前,每当我选择燃油类型或座椅容量时,所有汽车都会消失。

我所有的初始化:

const [timeRange, setTimeRange] = useState([]);
  const [fuelTypes, setFuelTypes] = useState([]); // all present fuel types in my DB (initialized in first useEffect)
  const [seatNumbers, setSeatNumbers] = useState([]); // all present seat capacity numbers in my DB (initialized in first useEffect)

  const [selectedTimeRange, setSelectedTimeRange] = useState([]);
  const [selectedFuelTypes, setSelectedFuelTypes] = useState([]); // selected fuel types (selected by the user from the antd Select.Option component)
  const [selectedSeatNumbers, setSelectedSeatNumbers] = useState([]); // selected seat numbers (selected by the user from the antd Select.Option component)

  const { loading } = useSelector((store) => store.alertsReducer);
  const [totalCars, setTotalCars] = useState([]);
  const dispatch = useDispatch();

回调的组件会更改我的状态(我正在使用antd

          <Select
            allowClear
            mode="multiple"
            placeholder="Fuel"
            style={{ width: "10%" }}
            onChange={(values) => {
              setSelectedFuelTypes(values);
            }}
          >
            {fuelTypes.map((fuelType, index) => {
              return (
                <Select.Option key={index} value={fuelType}>
                  {fuelType}
                </Select.Option>
              );
            })}
          </Select>
          <Select
            onChange={(values) => {
              setSelectedSeatNumbers(values);
            }}
            allowClear
            mode="multiple"
            placeholder="Seats"
            style={{ width: "10%" }}
          >
            {seatNumbers.map((seatNumber, index) => {
              return (
                <Select.Option key={index} value={seatNumber}>
                  {seatNumber}
                </Select.Option>
              );
            })}
          </Select>

我的所有使用effeffect s:

useEffect(() => {
    dispatch(getAllCars());
  }, []);

  useEffect(() => {
    setFuelTypes(
      [...new Set(cars.map((car) => car.fuelType.toLowerCase()))].sort()
    ); // all possible fuel types
    setSeatNumbers(
      [...new Set(cars.map((car) => car.capacity))].sort((a, b) => a - b)
    ); // all possible seat numbers
    setTotalCars(cars); // all cars
  }, [cars]);

  useEffect(() => {
    refilter();
  }, [selectedTimeRange, selectedFuelTypes, selectedSeatNumbers]);

我在启动时的refilter函数

function refilter() {
    setTotalCars(
      cars.filter(
        (car) =>
          selectedFuelTypes.includes(car.fuelType) &&
          selectedSeatNumbers.includes(car.capacity)
      )
    );
  }

选择过滤器(未显示汽车):

I am trying to filter an array of cars whenever any of my 2 filters changes. I run my own refilter function where I check all filters (not just the changed one), as you can see below. Any idea why it does not work? I am expecting to see cars satisfying the filters whenever I click a filter OR all the cars if no filters are applied. Currently, whenever I select a fuel type or seat capacity, all the cars disappear.

all my initializations:

const [timeRange, setTimeRange] = useState([]);
  const [fuelTypes, setFuelTypes] = useState([]); // all present fuel types in my DB (initialized in first useEffect)
  const [seatNumbers, setSeatNumbers] = useState([]); // all present seat capacity numbers in my DB (initialized in first useEffect)

  const [selectedTimeRange, setSelectedTimeRange] = useState([]);
  const [selectedFuelTypes, setSelectedFuelTypes] = useState([]); // selected fuel types (selected by the user from the antd Select.Option component)
  const [selectedSeatNumbers, setSelectedSeatNumbers] = useState([]); // selected seat numbers (selected by the user from the antd Select.Option component)

  const { loading } = useSelector((store) => store.alertsReducer);
  const [totalCars, setTotalCars] = useState([]);
  const dispatch = useDispatch();

the components whose callbacks change my states (I am using antd)

          <Select
            allowClear
            mode="multiple"
            placeholder="Fuel"
            style={{ width: "10%" }}
            onChange={(values) => {
              setSelectedFuelTypes(values);
            }}
          >
            {fuelTypes.map((fuelType, index) => {
              return (
                <Select.Option key={index} value={fuelType}>
                  {fuelType}
                </Select.Option>
              );
            })}
          </Select>
          <Select
            onChange={(values) => {
              setSelectedSeatNumbers(values);
            }}
            allowClear
            mode="multiple"
            placeholder="Seats"
            style={{ width: "10%" }}
          >
            {seatNumbers.map((seatNumber, index) => {
              return (
                <Select.Option key={index} value={seatNumber}>
                  {seatNumber}
                </Select.Option>
              );
            })}
          </Select>

all my useEffects:

useEffect(() => {
    dispatch(getAllCars());
  }, []);

  useEffect(() => {
    setFuelTypes(
      [...new Set(cars.map((car) => car.fuelType.toLowerCase()))].sort()
    ); // all possible fuel types
    setSeatNumbers(
      [...new Set(cars.map((car) => car.capacity))].sort((a, b) => a - b)
    ); // all possible seat numbers
    setTotalCars(cars); // all cars
  }, [cars]);

  useEffect(() => {
    refilter();
  }, [selectedTimeRange, selectedFuelTypes, selectedSeatNumbers]);

my refilter function

function refilter() {
    setTotalCars(
      cars.filter(
        (car) =>
          selectedFuelTypes.includes(car.fuelType) &&
          selectedSeatNumbers.includes(car.capacity)
      )
    );
  }

on startup:
enter image description here

on selecting a filter (no car shown):
enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ぽ尐不点ル 2025-02-07 05:18:28

我看不到任何地方定义的“汽车”,因此无法测试。我看到了总车辆,但没有汽车。

灌输者没有传递参数,并且正在使用汽车。那是全球吗?

I don't see "cars" defined anywhere and can't test it because of that. I see totalCars but not cars.

refilter has no parameters passed in, and it's using cars. Is that a global?

暮年慕年 2025-02-07 05:18:28

问题在于过滤逻辑,而不是使用效率或与反应严格相关的其他任何内容。这是完整的工作代码(可以改进,但这是一个工作解决方案):

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";

const { RangePicker } = DatePicker;

function Home() {
  const { cars } = useSelector((store) => {
    console.log("in callback:", store.carsReducer);
    return store.carsReducer;
  });

  const [timeRange, setTimeRange] = useState([]);
  const [fuelTypes, setFuelTypes] = useState([]); // all present fuel types in my DB (initialized in first useEffect)
  const [seatNumbers, setSeatNumbers] = useState([]); // all present seat capacity numbers in my DB (initialized in first useEffect)

  const [selectedTimeRange, setSelectedTimeRange] = useState([]);
  const [selectedFuelTypes, setSelectedFuelTypes] = useState([]); // selected fuel types (selected by the user from the antd Select.Option component)
  const [selectedSeatNumbers, setSelectedSeatNumbers] = useState([]); // selected seat numbers (selected by the user from the antd Select.Option component)

  const { loading } = useSelector((store) => store.alertsReducer);
  const [totalCars, setTotalCars] = useState([]);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getAllCars());
  }, []);

  useEffect(() => {
    setFuelTypes(
      [...new Set(cars.map((car) => car.fuelType.toLowerCase()))].sort()
    ); // all possible fuel types
    setSeatNumbers(
      [...new Set(cars.map((car) => car.capacity))].sort((a, b) => a - b)
    ); // all possible seat numbers
    setTotalCars(cars); // all cars
  }, [cars]);

  useEffect(() => {
    refilter();
  }, [selectedTimeRange, selectedFuelTypes, selectedSeatNumbers]);

  function refilter() {
    // no need for 3 separate functions (that would mean setting the state of the totalCars variable 3 times
    // using the `setTotalCars` function - which -if I am not mistaken- might trigger unexpected behavior
    // with the re-rendering of the component)
    // temporary array; eventually, totalCars will be assigned `temp` value using the `setTotalCars` method!
    var temp = [];

    // logica timeRange
    if (selectedTimeRange.length === 0) {
      console.log("user selected no time range");
      temp = [...cars];
    } else {
      console.log('user selected timeRange: ', selectedTimeRange);
      var selectedFrom = moment(selectedTimeRange[0], "MMM DD yyyy HH");
      var selectedTo = moment(selectedTimeRange[1], "MMM DD yyyy HH");

      for (var car of cars) {
        if (car.bookedTimeSlots.length == 0) {
          temp.push(car);
        } else {
          var toBeAdded = 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)) {
                  toBeAdded = false; // if time range of booking overlaps with selected time range, don't add car to temp!
                  break;
            }
          }
          if (toBeAdded) {
            temp.push(car);
          }
        }
      }
    }

    // fuelTypes logic
    if (selectedFuelTypes.length !== 0){
      console.log('User selected fuel types: ', selectedFuelTypes);
      temp = temp.filter((car) => selectedFuelTypes.includes(car.fuelType));
      console.log(`filtered by fuelTypes: ${temp}`);
    }

    // seatsNumber logic
    if (selectedSeatNumbers.length !== 0){
      console.log('User selected seat numbers: ', selectedSeatNumbers);
      temp = temp.filter((car) => selectedSeatNumbers.includes(car.capacity));
      console.log(`filtered by seatsNumber: ${temp.length}`);
    }

    // finally, assign filtered values to totalCars!
    console.log("temp:", temp);
    setTotalCars(temp);
  }

  return (
    <DefaultLayout>
      <Row className="mt-3" justify="center">
        <Col lg={20} sm={24} className="d-flex justify-content-left">
          <RangePicker
            showTime={{ format: "HH:mm" }}
            format="MMM DD yyyy HH:mm"
            onChange={(values) => {
              setSelectedTimeRange(values);
            }}
          />
          <Select
            allowClear
            mode="multiple"
            placeholder="Fuel"
            style={{ width: "10%" }}
            onChange={(values) => {
              setSelectedFuelTypes(values);
            }}
          >
            {fuelTypes.map((fuelType, index) => {
              return (
                <Select.Option key={index} value={fuelType}>
                  {fuelType}
                </Select.Option>
              );
            })}
          </Select>
          <Select
            onChange={(values) => {
              setSelectedSeatNumbers(values);
            }}
            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;

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):

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";

const { RangePicker } = DatePicker;

function Home() {
  const { cars } = useSelector((store) => {
    console.log("in callback:", store.carsReducer);
    return store.carsReducer;
  });

  const [timeRange, setTimeRange] = useState([]);
  const [fuelTypes, setFuelTypes] = useState([]); // all present fuel types in my DB (initialized in first useEffect)
  const [seatNumbers, setSeatNumbers] = useState([]); // all present seat capacity numbers in my DB (initialized in first useEffect)

  const [selectedTimeRange, setSelectedTimeRange] = useState([]);
  const [selectedFuelTypes, setSelectedFuelTypes] = useState([]); // selected fuel types (selected by the user from the antd Select.Option component)
  const [selectedSeatNumbers, setSelectedSeatNumbers] = useState([]); // selected seat numbers (selected by the user from the antd Select.Option component)

  const { loading } = useSelector((store) => store.alertsReducer);
  const [totalCars, setTotalCars] = useState([]);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getAllCars());
  }, []);

  useEffect(() => {
    setFuelTypes(
      [...new Set(cars.map((car) => car.fuelType.toLowerCase()))].sort()
    ); // all possible fuel types
    setSeatNumbers(
      [...new Set(cars.map((car) => car.capacity))].sort((a, b) => a - b)
    ); // all possible seat numbers
    setTotalCars(cars); // all cars
  }, [cars]);

  useEffect(() => {
    refilter();
  }, [selectedTimeRange, selectedFuelTypes, selectedSeatNumbers]);

  function refilter() {
    // no need for 3 separate functions (that would mean setting the state of the totalCars variable 3 times
    // using the `setTotalCars` function - which -if I am not mistaken- might trigger unexpected behavior
    // with the re-rendering of the component)
    // temporary array; eventually, totalCars will be assigned `temp` value using the `setTotalCars` method!
    var temp = [];

    // logica timeRange
    if (selectedTimeRange.length === 0) {
      console.log("user selected no time range");
      temp = [...cars];
    } else {
      console.log('user selected timeRange: ', selectedTimeRange);
      var selectedFrom = moment(selectedTimeRange[0], "MMM DD yyyy HH");
      var selectedTo = moment(selectedTimeRange[1], "MMM DD yyyy HH");

      for (var car of cars) {
        if (car.bookedTimeSlots.length == 0) {
          temp.push(car);
        } else {
          var toBeAdded = 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)) {
                  toBeAdded = false; // if time range of booking overlaps with selected time range, don't add car to temp!
                  break;
            }
          }
          if (toBeAdded) {
            temp.push(car);
          }
        }
      }
    }

    // fuelTypes logic
    if (selectedFuelTypes.length !== 0){
      console.log('User selected fuel types: ', selectedFuelTypes);
      temp = temp.filter((car) => selectedFuelTypes.includes(car.fuelType));
      console.log(`filtered by fuelTypes: ${temp}`);
    }

    // seatsNumber logic
    if (selectedSeatNumbers.length !== 0){
      console.log('User selected seat numbers: ', selectedSeatNumbers);
      temp = temp.filter((car) => selectedSeatNumbers.includes(car.capacity));
      console.log(`filtered by seatsNumber: ${temp.length}`);
    }

    // finally, assign filtered values to totalCars!
    console.log("temp:", temp);
    setTotalCars(temp);
  }

  return (
    <DefaultLayout>
      <Row className="mt-3" justify="center">
        <Col lg={20} sm={24} className="d-flex justify-content-left">
          <RangePicker
            showTime={{ format: "HH:mm" }}
            format="MMM DD yyyy HH:mm"
            onChange={(values) => {
              setSelectedTimeRange(values);
            }}
          />
          <Select
            allowClear
            mode="multiple"
            placeholder="Fuel"
            style={{ width: "10%" }}
            onChange={(values) => {
              setSelectedFuelTypes(values);
            }}
          >
            {fuelTypes.map((fuelType, index) => {
              return (
                <Select.Option key={index} value={fuelType}>
                  {fuelType}
                </Select.Option>
              );
            })}
          </Select>
          <Select
            onChange={(values) => {
              setSelectedSeatNumbers(values);
            }}
            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;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文