【问题标题】:Filtering function running one step too late过滤功能运行太晚了一步
【发布时间】:2020-07-17 10:12:11
【问题描述】:

我正在构建一个组件来过滤数据数组。

有 2 个过滤器,一个用于团队,一个用于位置。当每个下拉列表都更改时,我正在更改团队和位置的状态变量,然后运行过滤器功能。

由于某种原因,过滤器运行得太晚了。

举个例子 - 如果我选择 Team A,什么都不会更新。如果我随后选择 Team B,careersDataFiltered 变量将显示 Team A。如果我选​​择 Team C,它将显示 Team B 的数据。

这几乎就像它跑得太晚了。

您可以从代码中看到我在设置状态变量后运行过滤器,这就是为什么这对我来说有点让人头疼。

import React, { useState } from "react"

import { motion, AnimatePresence } from "framer-motion"

const careersData = [
  {
    name: "X Job Title",
    url: "/url/x",
    team: "Team a",
    location: "London",
  },
  {
    name: "M Job Title",
    url: "/url/m",
    team: "Team a",
    location: "London",
  },
  {
    name: "B Job Title",
    url: "/url/b",
    team: "Team c",
    location: "Sheffield",
  },
  {
    name: "A Job Title",
    url: "/url/a",
    team: "Team b",
    location: "London",
  },
  {
    name: "F Job Title",
    url: "/url/f",
    team: "Team b",
    location: "Sheffield",
  },
  {
    name: "C Job Title",
    url: "/url/c",
    team: "Team c",
    location: "London",
  },
  {
    name: "Q Job Title",
    url: "/url/q",
    team: "Team a",
    location: "Sheffield",
  },
]

const uniqueTeams = []
const uniqueLocations = []

// Build the unique values
if (careersData !== null) {
  careersData.map(career => {
    if (uniqueTeams.indexOf(career.team) === -1) {
      return uniqueTeams.push(career.team)
    }
  })
}

if (careersData !== null) {
  careersData.map(career => {
    if (uniqueLocations.indexOf(career.location) === -1) {
      return uniqueLocations.push(career.location)
    }
  })
}

// reorder ready for output
uniqueTeams.sort()
uniqueLocations.sort()

const CurrentVacancies = () => {
  const [careersDataFiltered, setCareersDataFiltered] = useState(careersData)
  const [filterTeam, setFilterTeam] = useState("")
  const [filterLocation, setFilterLocation] = useState("")

  // filter array based on values
  const runFilter = () => {
    // reset the filter data
    setCareersDataFiltered(careersData)

    if (filterTeam !== "") {
      setCareersDataFiltered(
        careersDataFiltered.filter(career => career.team === filterTeam)
      )
    }
    if (filterLocation !== "") {
      careersDataFiltered(
        careersDataFiltered.filter(career => career.location === filterLocation)
      )
    }
    console.log(careersDataFiltered)
  }

  return (
    <>
      <div className="flex">
        <h2 className="mr-auto">Current Vacancies</h2>
        <div className="">
          <select
            onChange={e => {
              setFilterTeam(e.target.value)
              runFilter()
            }}
          >
            <option value="">Team</option>
            {uniqueTeams.map(team => (
              <option key={team} value={team}>
                {team}
              </option>
            ))}
          </select>
          <select
            onChange={e => {
              setFilterLocation(e.target.value)
              runFilter()
            }}
          >
            <option value="">Location</option>
            {uniqueLocations.map(location => (
              <option key={location} value={location}>
                {location}
              </option>
            ))}
          </select>
        </div>
      </div>

      <div>
        <AnimatePresence>
          {careersDataFiltered.map((career, index) => (
            <motion.div
              key={index}
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              positionTransition
            >
              <div>
                <div className="text-sm">
                  {career.name} - {career.team} | {career.location}
                </div>
              </div>
            </motion.div>
          ))}
        </AnimatePresence>
      </div>
    </>
  )
}

export default CurrentVacancies

【问题讨论】:

    标签: javascript reactjs jsx


    【解决方案1】:

    首先你的代码有一些错误,你应该在runFilter()的第二个if语句中使用setCareersDataFiltered()。另外setCareersDataFiltered()async,所以你不能在调用setCareersDataFiltered() 之后立即使用careersDataFiltered。调用setFilterTeam() 也是如此,因为您在runFilter() 中使用filterTeam,因此您不能在调用setFilterTeam() 后调用runFilter(),因为不能保证您的数据会更新。 setFilterLocation() 也是如此。

    runFilter() 放在useEffect() 中,这样当runFilter() 的任何依赖项发生变化时,它就会调用它。

     useEffect(() => {
        runFilter();
      }, [runFilter]);
    

    同时更改runFilter() 如下并使用useCallback() 来防止重新渲染循环。

    // filter array based on values
      const runFilter = useCallback(() => {
        let filter = careersData;
        if (filterTeam !== "") {
          filter = filter.filter(career => career.team === filterTeam);
        }
        if (filterLocation !== "") {
          filter = filter.filter(career => career.location === filterLocation);
        }
        setCareersDataFiltered(filter);
      }, [filterLocation, filterTeam]);
    

    最后删除对runFilter()的任何手动调用;

    作为提示,我认为您的过滤器逻辑也有错误,因为我可以将团队设置为 A,然后它只显示 A,但如果我设置位置,它会应用位置过滤器并忽略 A 过滤器,这是因为 async 问题.因此,如果您想同时应用两个过滤器,您应该在runFilter() 中混合使用两个 if 语句。我混合了过滤器并编写了一个新的过滤器例程。

    Here is my working demo version

    【讨论】:

      【解决方案2】:

      Ciao,这个问题可能与你如何在函数runFilter 中设置careersDataFiltered 有关。就我个人的经验而言,直接读取和设置状态绝不是一个好主意。尝试像这样更改runFilter

      const runFilter = () => {
      let temp_careersDataFiltered = _.cloneDeep(careersData); //here you have to clone deep careersData because javascript keep reference (I use cloneDeep from lodash)
      
      if (filterTeam !== "") {
        temp_careersDataFiltered = careersData.filter(career => career.team === filterTeam)
      }
      if (filterLocation !== "") {
        temp_careersDataFiltered = careersData.filter(career => career.location === filterLocation)
      
      }
      
      setCareersDataFiltered(
          temp_careersDataFiltered 
      )
      console.log(temp_careersDataFiltered) 
      }
      

      解释:由于您不确定调用setCareersDataFilteredcareersDataFiltered 的值是否立即可用,因此将过滤器应用于temp_careersDataFiltered 临时数组并最终设置careersDataFiltered 以重新渲染组件。 我正在克隆 careersData,因为您知道 javascript 可以参考,如果您编写 let temp_careersDataFiltered = careersData,如果您修改 temp_careersDataFiltered,实际上您也在修改 careersData

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-03
        • 2012-05-17
        • 1970-01-01
        相关资源
        最近更新 更多