反应钩子setState落后一步

时间:2020-07-20 11:56:16

标签: reactjs react-hooks

我有此复选框输入,当我单击它时,我将其取值并添加到名为vendorFilters的状态数组中,但似乎状态总是落后了1步,我在使用类组件,我认为切换到挂钩可能会解决问题但是没有。

我附上了codesandbox链接,请看一下。

https://codesandbox.io/s/naughty-brattain-89hxi?file=/src/App.js

import React, { useState, useEffect } from "react";
import "./styles.css";
import raw from "./data.json";

const App = () => {
  const [data, setData] = useState([]);
  const [vendorFilters, setVendorFilters] = useState([]);
  const [capacityFilters, setCapacityFilters] = useState([]);
  const [speedFilters, setSpeedFilters] = useState([]);
  const [cycleLatencyFilters, setCycleLatencyFilters] = useState([]);
  const [colorFilters, setColorFilters] = useState([]);
  const [vendorQuantity, setVendorQuantity] = useState([0, 0, 0, 0, 0, 0]);

  useEffect(() => setData(raw), []);

  const inputHandler = event => {
    updateFiltersArrays(
      event.target.value,
      event.target.name,
      event.target.checked
    );
    console.log(vendorFilters);
    filterFunction();
  };

  const filterFunction = () => {
    const filteredData1 = data.filter(object => {
      if (vendorFilters.length === 0) return true;
      return vendorFilters.includes(object.vendor);
    });
    const filteredData2 = filteredData1.filter(({ capacity }) => {
      if (capacityFilters.length === 0) return true;
      return capacityFilters.includes(capacity.toString());
    });
    const filteredData3 = filteredData2.filter(({ speed }) => {
      if (speedFilters.length === 0) return true;
      return speedFilters.includes(speed.toString());
    });
    const filteredData4 = filteredData3.filter(({ cycleLatency }) => {
      if (cycleLatencyFilters.length === 0) return true;
      return cycleLatencyFilters.includes(cycleLatency.toString());
    });
    const filteredData5 = filteredData4.filter(({ color }) => {
      if (colorFilters.length === 0) return true;
      return colorFilters.includes(color.toString());
    });
    console.log("hikhan");
    const vendor = [0, 0, 0, 0, 0, 0];
    vendor[0] = filteredData5.filter(
      object => object.vendor === "BESTRAM" && vendorFilters.includes("BESTRAM")
    ).length;
  };

  const updateFiltersArrays = (input, collection, checked) => {
    switch (collection) {
      case "vendor":
        if (checked) {
          setVendorFilters([...vendorFilters, input]);
        } else {
          const filters = vendorFilters.filter(f => f !== input);
          setVendorFilters(filters);
        }

        break;
      case "capacity":
        if (checked) {
          setCapacityFilters(prev => [...prev, input]);
        } else {
          const filters = vendorFilters.filter(f => f !== input);
          setCapacityFilters(filters);
        }

        break;
      case "speed":
        if (checked) {
          setSpeedFilters(prev => [...prev, input]);
        } else {
          const filters = vendorFilters.filter(f => f !== input);
          setSpeedFilters(filters);
        }

        break;
      case "cycleLatency":
        if (checked) {
          setCycleLatencyFilters(prev => [...prev, input]);
        } else {
          const filters = vendorFilters.filter(f => f !== input);
          setCycleLatencyFilters(filters);
        }

        break;
      case "color":
        if (checked) {
          setColorFilters(prev => [...prev, input]);
        } else {
          const filters = vendorFilters.filter(f => f !== input);
          setColorFilters(filters);
        }

        break;
      default:
        break;
    }
  };

  return (
    <div class="main-content">
      <h1>Filter Predictions</h1>
      <div class="filter">
        <div class="group" data-test="vendor-group">
          <div class="group__name">vendor</div>
          <label class="group__item" data-test="item-BESTRAM">
            <input
              type="checkbox"
              value="BESTRAM"
              name="vendor"
              onClick={inputHandler}
            />
            BESTRAM ({vendorQuantity[0]})
          </label>
          <label class="group__item" data-test="item-Rocket">
            <input
              type="checkbox"
              value="Rocket"
              name="vendor"
              onClick={inputHandler}
            />
            Rocket ()
          </label>
          <label class="group__item" data-test="item-gTech">
            <input
              type="checkbox"
              value="gTech"
              name="vendor"
              onClick={inputHandler}
            />
            gTech ({vendorQuantity[2]})
          </label>
          <label class="group__item" data-test="item-5Byte">
            <input
              type="checkbox"
              value="5Byte"
              name="vendor"
              onClick={inputHandler}
            />
            5Byte ({vendorQuantity[3]})
          </label>
          <label class="group__item" data-test="item-Xdata">
            <input
              type="checkbox"
              value="Xdata"
              name="vendor"
              onClick={inputHandler}
            />
            Xdata ({vendorQuantity[4]})
          </label>
          <label class="group__item" data-test="item-Abc">
            <input
              type="checkbox"
              value="Abc"
              name="vendor"
              onClick={inputHandler}
            />
            Abc ({vendorQuantity[5]})
          </label>
        </div>
        <div class="group" data-test="capacity-group">
          <div class="group__name">capacity</div>
          <label class="group__item" data-test="item-4">
            <input
              type="checkbox"
              value={4}
              name="capacity"
              onClick={inputHandler}
            />
            4 GB ()
          </label>
          <label class="group__item" data-test="item-8">
            <input
              type="checkbox"
              value={8}
              name="capacity"
              onClick={inputHandler}
            />
            8 GB ()
          </label>
          <label class="group__item" data-test="item-32">
            <input
              type="checkbox"
              value={32}
              name="capacity"
              onClick={inputHandler}
            />
            32 GB ()
          </label>
          <label class="group__item" data-test="item-16">
            <input
              type="checkbox"
              value={16}
              name="capacity"
              onClick={inputHandler}
            />
            16 GB ()
          </label>
        </div>
        <div class="group" data-test="speed-group">
          <div class="group__name">speed</div>
          <label class="group__item" data-test="item-2400">
            <input
              type="checkbox"
              value={2400}
              name="speed"
              onClick={inputHandler}
            />
            2400 MHz (80)
          </label>
          <label class="group__item" data-test="item-2666">
            <input
              type="checkbox"
              value={2666}
              name="speed"
              onClick={inputHandler}
            />
            2666 MHz (30)
          </label>
          <label class="group__item" data-test="item-3333">
            <input
              type="checkbox"
              value={3333}
              name="speed"
              onClick={inputHandler}
            />
            3333 MHz (25)
          </label>
          <label class="group__item" data-test="item-3200">
            <input
              type="checkbox"
              value={3200}
              name="speed"
              onClick={inputHandler}
            />
            3200 MHz (23)
          </label>
          <label class="group__item" data-test="item-3600">
            <input
              type="checkbox"
              value={3600}
              name="speed"
              onClick={inputHandler}
            />
            3600 MHz (21)
          </label>
          <label class="group__item" data-test="item-4000">
            <input
              type="checkbox"
              value={4000}
              name="speed"
              onClick={inputHandler}
            />
            4000 MHz (21)
          </label>
        </div>
        <div class="group" data-test="cycle-latency-group">
          <div class="group__name">cycle latency</div>
          <label class="group__item" data-test="item-CL-7">
            <input
              type="checkbox"
              value={"CL 7"}
              name="cycleLatency"
              onClick={inputHandler}
            />
            CL 7 (54)
          </label>
          <label class="group__item" data-test="item-CL-9">
            <input
              type="checkbox"
              value={"CL 9"}
              name="cycleLatency"
              onClick={inputHandler}
            />
            CL 9 (51)
          </label>
          <label class="group__item" data-test="item-CL-12">
            <input
              type="checkbox"
              value={"CL 12"}
              name="cycleLatency"
              onClick={inputHandler}
            />
            CL 12 (51)
          </label>
          <label class="group__item" data-test="item-CL-11">
            <input
              type="checkbox"
              value={"CL 11"}
              name="cycleLatency"
              onClick={inputHandler}
            />
            CL 11 (44)
          </label>
        </div>
        <div class="group" data-test="color-group">
          <div class="group__name">color</div>
          <label class="group__item" data-test="item-Green">
            <input
              type="checkbox"
              value={"Green"}
              name="color"
              onClick={inputHandler}
            />
            Green (94)
          </label>
          <label class="group__item" data-test="item-Black">
            <input
              type="checkbox"
              value={"Black"}
              name="color"
              onClick={inputHandler}
            />
            Black (50)
          </label>
          <label class="group__item" data-test="item-Red">
            <input
              type="checkbox"
              value={"Red"}
              name="color"
              onClick={inputHandler}
            />
            Red (31)
          </label>
          <label class="group__item" data-test="item-White">
            <input
              type="checkbox"
              value={"White"}
              name="color"
              onClick={inputHandler}
            />
            White (25)
          </label>
        </div>
      </div>
    </div>
  );
};

export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

2 个答案:

答案 0 :(得分:0)

setState是一个异步函数,它需要一些时间来更新状态。它不是瞬时的。这是因为setState更改状态并导致重新呈现。这可能是一项昂贵的操作,并且使其同步可能会使浏览器无响应。因此,setState调用是异步的,也可以是批处理的,以便获得更好的UI体验和性能。

幸运的是,setState进行了回调:

this.setState({ param: "param" }, () => {                              
        //callback
        console.log(this.state.param) // your param
      });

答案 1 :(得分:0)

setState是一个异步函数,因此array的值可能尚未更新。在下一个渲染周期中它将具有更新的值。

解决方案是使用useEffect react hook

 const inputHandler = event => {
    updateFiltersArrays(
      event.target.value,
      event.target.name,
      event.target.checked
    );
    // remove function call from here
  };
const filterFunction = useCallback(()=>{
  // rest of the code
},[])

useEffect(()=>{
  console.log(vendorFilters); // will have updated value
  filterFunction()
},[vendorFilters,filterFunction])

以上代码指出,vendorFilter发生更改时,请运行此功能