在 React 中使用复选框按钮过滤数据

Filter data with checkbox buttons in React

我想根据按下多个复选框按钮来过滤数据。目前只有最近按下的按钮起作用并显示输出,而不是同时显示其他按钮的输出。

复选框按钮的状态正常工作,即单击时为真,未单击时为假 - 但是我不确定如何将它与获取数据的 find 函数连接。

 const JobsList = (props) => {

  const pageNumber = props.pageNumber || 1;
  const [jobs, setJobs] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  const [page, setPage] = useState(pageNumber);
  const [pages, setPages] = useState(1);

  useEffect(() => {
    const fetchJobs = async () => {
      try {
        retrieveJobs();
        retrievePages();
        pages = retrievePages();
        setJobs(jobs);
        setLoading(false);
      } catch (error) {
        console.log(error);
        setLoading(false);
        setError("Some error occured");
      }
    };
    fetchJobs();
  }, [page]);

  const retrievePages = () => {
    JobDataService.getPage(pages)
      .then((response) => {
        setPages(response.data.totalPages);
      })
      .catch((e) => {
        console.log(e);
      });
  };
  const Checkbox = ({ type = "checkbox", name, checked = false, onChange }) => {
    return (
      <input
        type={type}
        name={name}
        checked={checked}
        onChange={onChange}
        className="btn--position"
      />
    );
  };
 //plain object as state
  const [checkedItems, setCheckedItems] = useState({}); //plain object as state
  const filteredItems = [];
  const handleChange = (event) => {
    // updating an object instead of a Map
    setCheckedItems({
      ...checkedItems,
      [event.target.name]: event.target.checked,
      filteredItems.
    });
    console.log("from HANDLECHANGE: ", checkedItems)
    // console.log(checkedItems[event.target.checked])
    // find(event.target.name)
  };

  useEffect(() => {
    console.log("checkedItems from UseEffect: ", checkedItems);
    // console.log(checkedItems)
    // find(checkedItems)
  }, [checkedItems]);
  const checkboxes = [
    {
      name: "‍♀️ Finance",
      key: "financeKey",
      label: "financeLabel",
    },
    {
      name: "‍ Marketing",
      key: "marketingKey",
      label: "marketingLabel",
    },
    {
      name: "‍ Sales",
      key: "salesKey",
      label: "salesLabel",
    },
    {
      name: " Operations",
      key: "operationsKey",
      label: "financeLabel",
    },
    {
      name: "‍ Software Engineering",
      key: "softwareEngineeringKey",
      label: "softwareEngineeringLabel",
    },
  ];

  const retrieveJobs = () => {
    JobDataService.getAll(page)
      .then((response) => {
        console.log(response.data);
        setJobs(response.data.jobs);
      })
      .catch((e) => {
        console.log(e);
      });
  };
  const refreshList = () => {
    retrieveJobs();
  };

  const find = (query, by) => {
    JobDataService.find(query, by)
      .then((response) => {
        console.log(response.data);
        setJobs(response.data.jobs);
        // setPage(response.data.total_results)
        setPages(response.data.totalPages);
      })
      .catch((e) => {
        console.log(e);
      });
  };

  return (
        <div className="hero-container">
          <div>
            <div className="allButtons-div">
              <div className="buttons-div">
                <div>
                  <label>
                    {checkedItems[""]}
                    {/* Checked item name : {checkedItems["check-box-1"]}{" "} */}
                  </label>
                  {checkboxes.map((item) => (
                    <label key={item.key}>
                      {item.name}
                      <Checkbox
                        name={item.name}
                        checked={checkedItems[item.name]}
                        onChange={handleChange}
                      />
                    </label>
                  ))}
                </div>
</div>
</div>
</div>
</div>
);

下面的函数从 MongoDB 领域数据库

中获取数据
  const find = (query, by) => {
    JobDataService.find(query, by)
      .then((response) => {
        setJobs(response.data.jobs);
        setPages(response.data.totalPages);
      })
      .catch((e) => {
        console.log(e);
      });
  };

为了回答您的问题,我们的 find() 函数应该很像您的 retrieveJobs() 和 retrievePages() 函数 - 它们与您应用程序的数据层交互。也就是说,如果我们要做的只是过滤我们已经拥有的数据(假设 retrieveJobs() 和 retrievePages() 获取您需要的所有作业和页面),那么我们不需要重新获取基于您 UI 中检查的数据 - 我们只需要使用 JavaScript 通过使用您应该已经熟悉的东西来过滤结果,例如 map()、sort()、reduce()、filter ()等

更进一步,这段代码有很多问题。我们使用的状态可能比我们应该的多一点,我们在多个地方冗余地设置状态,我们使用的 useEffect() 调用不做太多,这个列表还在继续。我去过那里 - 尝试以“React”方式做事有时会导致相反的效果,你会迷失在无休止的 useState() 和 useEffect() 调用中,并试图找出在哪里调用什么事件处理程序为什么。我已经完成并对您的代码进行了一些相当明显的更改,希望能让您走上正确的轨道,更好地理解未来发生的事情,但我强烈建议您阅读 React 文档并阅读 this post由丹·阿布拉莫夫 (Dan Abramov) 撰写,直到您理解为止(我不得不一遍又一遍地阅读并重新阅读该文章中的几个段落,然后才点击它,但我认为它会对您有很长的路要走)。

这是代码,它可能还有很多问题,但祝你好运!

// Since this is a constant set of data, you don't need to include it in your component; remember
// that React components are just regular old functions, so having this constant array value in your
// component means that it's being created anew every render. Let's move it above the component.
const checkboxes = [
  {
    name: '‍♀️ Finance',
    key: 'financeKey',
    label: 'financeLabel',
  },
  {
    name: '‍ Marketing',
    key: 'marketingKey',
    label: 'marketingLabel',
  },
  {
    name: '‍ Sales',
    key: 'salesKey',
    label: 'salesLabel',
  },
  {
    name: ' Operations',
    key: 'operationsKey',
    label: 'financeLabel',
  },
  {
    name: '‍ Software Engineering',
    key: 'softwareEngineeringKey',
    label: 'softwareEngineeringLabel',
  },
];

// the same principle applies with this smaller component. It doesn't use 
// state or props from JobsList, so we should move the component outside of 
// your JobsList component to make sure it's not created over and over again
// on each render; let's move it outside of JobsList
const Checkbox = ({ type = 'checkbox', name, checked = false, onChange }) => {
  return (
    <input
      type={type}
      name={name}
      checked={checked}
      onChange={onChange}
      className="btn--position"
    />
  );
};

// Since these functions seem to interact with the data layer of your app (depending on how JobDataService works of course),
// why don't we try making them functions that return a value from the data layer? Also, it looks like we're using async/await
// syntax in our useEffect call, why don't we try that here?
const retrievePages = async (pages) => {
  try {
    const response = await JobDataService.getPage(pages);
    return response;
  } catch (e) {
    console.log(e);
  }
};

// as an aside, I'm not sure of the difference between pages and page, but we'll keep this the same for now
const retrieveJobs = async (page) => {
  try {
    const response = await JobDataService.getAll(page);
    return response;
  } catch (e) {
    console.log(e);
  }
};

// to hopefully kind of answer your question, this find() function is a lot like the retrieveJobs and retrievePages functions above:
// it just interacts with your data layer - let's try and make it an async function and pull it out of the component so it can return
// results we need. As I explained above, though, if we grabbed all of our jobs and all of our pages already and just need to filter 
// the data, why do we need to make a network call for that? Surely we can just use JS functions like filter(), map(), sort(), and reduce()
// to filter the results into the structures that our app needs
const find = async (query, by) => {
  try {
    const response = await JobDataService.find(query, by);
    return response;
  } catch (e) {
    console.log(e);
  }
};

const JobsList = (props) => {
  const pageNumber = props.pageNumber || 1;
  const [jobs, setJobs] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  // if pageNumber is passed as a prop, why do we need to store it in state? Presumably the parent component
  // of <JobsList /> will handle keeping track of pageNumber, which is why we pass data as props. Let's comment
  // out this useState call
  // const [page, setPage] = useState(pageNumber);
  const [pages, setPages] = useState(1);

  useEffect(() => {
    const fetchJobs = async () => {
      try {
        const jobsData = await retrieveJobs(props.page);
        const pageData = await retrievePages(pages);
        setJobs(jobsData);
        setPages(pageData);
        // why do we call retrievePages() twice? also, you've decided to store pages in state, so we'll want to use setPages
        // for this instead of a normal assignment. let's comment out this assignment
        // pages = retrievePages();
        setLoading(false);
      } catch (error) {
        console.log(error);
        setLoading(false);
        setError('Some error occured');
      }
    };
    fetchJobs();
  }, [props.page, pages]);

  const [checkedItems, setCheckedItems] = useState({});
  // this is where we could do things like filter based on the checked items instead of making another network call; we have all of our data,
  // we just need to do stuff with it (this is contrived but hopfully you get the idea) - every time React re-renders the JobsList component based on a new set of state or props (think something gets checked or unchecked),
// we'll just filter the data we've already fetched based on that new reality
  const filteredJobs = jobs.filter((job) => job.id === checkedItems[job.id]);
  const filteredPages = pages.filter((page) => page.id === checkedItems[page.id]);
  const handleChange = (event) => {
    // updating an object instead of a Map
    setCheckedItems({
      ...checkedItems,
      [event.target.name]: event.target.checked,
      // not sure what this is, perhaps a typo; let's comment it out
      // filteredItems.
    });
    // this find call needs two arguments, no? let's comment it out for now
    // find(event.target.name)
  };

  // not sure of the purpose behind this second useEffect call, let's comment it out
  // useEffect(() => {
  //   console.log("checkedItems from UseEffect: ", checkedItems);
  //   // console.log(checkedItems)
  //   // find(checkedItems)
  // }, [checkedItems]);

  // we'll ignore this for now as well and comment it out, we should probably be refreshing our data based on state or prop updates
  // const refreshList = () => {
  //   retrieveJobs();
  // };

  return (
    <div className="hero-container">
      <div>
        <div className="allButtons-div">
          <div className="buttons-div">
            <div>
              <label>
                {checkedItems['']}
                {/* Checked item name : {checkedItems["check-box-1"]}{" "} */}
              </label>
              {checkboxes.map((item) => (
                <label key={item.key}>
                  {item.name}
                  <Checkbox
                    name={item.name}
                    checked={checkedItems[item.name]}
                    onChange={handleChange}
                  />
                </label>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};