首页 > 解决方案 > 使用 React Hooks 过滤同一组件上的两组输入数据

问题描述

我有两个输入,并试图让它们过滤掉单独的数据。我正在为过滤器使用 NPM 包,它对第一个输入非常有效,因为它根据卡上的任何条件返回。我需要根据事后添加的标签返回第二个输入。我觉得这是一个简单的答案,但我有点新,所以我无法让它工作。我尝试使用上下文从任何组件获取状态,但无论哪种方式,我这样做我仍然无法过滤它。任何反馈或帮助将不胜感激 - 谢谢:)

主要的.jsx

import React from "react";
import axios from "axios";
import { useState, useEffect, useContext } from "react";
import TagProvider from "../context/TagContext";
import { TagContext } from "../context/TagContext";
import Card from "./Card/Card";
import "./Main.scss";
import FilterResults from "react-filter-search";

export default function Main() {
  //using state with hooks
  const [students, setStudents] = useState([]);
  const [value, setValue] = useState("");
  const [valueTwo, setValueTwo] = useContext(TagContext);

  // axios call to get data
  const url = "https://api.hatchways.io/assessment/students";
  const getData = () => {
    axios
      .get(`${url}`)
      .then((res) => {
        const studentData = res.data.students;
        setStudents(studentData);
      })
      .catch((error) => console.log(`Error: ${error}`));
  };
  useEffect(() => {
    getData();
  }, []);

  // handleChange function for filter results

  let handleChange = (event) => {
    const { value } = event.target;
    setValue(value);
  };

  let handleChangeTwo = (event) => {
    const { valueTwo } = event.target;
    setValueTwo(valueTwo);
  };

  return (
    <>
      <TagProvider>
        <div className="main">
          <input
            type="text"
            className="main__search"
            value={value}
            placeholder="Search by name"
            onChange={handleChange}
          />
          <input
            type="text"
            className="main__search"
            value={valueTwo}
            placeholder="Search by tag"
            onChange={handleChangeTwo}
          />

          <FilterResults
            value={value}
            data={students}
            renderResults={(results) => (
              <div className="main__container">
                {results.map((item) => (
                  <Card
                    key={item.id}
                    email={item.email}
                    company={item.company}
                    skill={item.skill}
                    firstname={item.firstName}
                    lastname={item.lastName}
                    grades={item.grades}
                    pic={item.pic}
                  />
                ))}
              </div>
            )}
          />
        </div>
      </TagProvider>
    </>
  );
}

卡片.jsx

import React, { useState, useRef } from "react";
import "./Card.scss";
import Tags from "../Tags/Tags";
import TagProvider from "../../context/TagContext";

export default function Card(props) {
  const [setActive, setActiveState] = useState("");
  const [setHeight, setHeightState] = useState("0px");
  const content = useRef(null);

  function toggleAccordion() {
    setActiveState(setActive === "" ? "active" : "");
    setHeightState(
      setActive === "active" ? "0px" : `${content.current.scrollHeight}px`
    );
  }
  // convert string to integer
  let result = props.grades.map((x) => {
    return parseInt(x, 10);
  });

  // caluclate average function
  const average = (nums) => nums.reduce((a, b) => a + b) / nums.length;

  const gradeTitle = [
    "Test 1:",
    "Test 2:",
    "Test 3:",
    "Test 4:",
    "Test 5:",
    "Test 6:",
    "Test 7:",
    "Test 8:",
  ];

  return (
    <div>
      {/* Card Section */}
      <div className="card__container">
        <img className="card__image" src={props.pic} alt="avatar" />
        <div className="card__container-two">
          <div className="card__container-plus">
            <h1 className="card__name">
              {props.firstname} {props.lastname}
            </h1>
            <button className="card__button" onClick={toggleAccordion}>
              &#43;
            </button>
          </div>
          <div className="card__container-three">
            <div className="card__info">Email: {props.email}</div>
            <div className="card__info">Company: {props.company}</div>
            <div className="card__info">Skill: {props.skill}</div>
            <div className="card__info">Average: {average(result)}%</div>
          </div>
        </div>
      </div>

      <TagProvider>
        <Tags />
      </TagProvider>

      {/* Card Expansion */}
      <div className="accordion">
        <div
          ref={content}
          style={{ maxHeight: `${setHeight}` }}
          className="accordion__content"
        >
          <div className="accordion__tests">
            <div className="accordion__test-title">
              {gradeTitle.map((title) => (
                <div>{title}</div>
              ))}
            </div>
            <div className="accordion__test-results">
              {result.map((number) => (
                <li>{number}%</li>
              ))}
            </div>
          </div>

          <div
            className="accordion__text"
            dangerouslySetInnerHTML={{ __html: props.content }}
          />
        </div>
      </div>
    </div>
    // </TagContext.Provider>
  );
}

标签.jsx

import React, { useContext } from "react";
import { X } from "react-feather";
import "./Tags.scss";
import { TagContext } from "../../context/TagContext";
import TagProvider from "../../context/TagContext";

export default function Tags() {
  const [tags, setTags] = useContext(TagContext);

  return (
    <TagProvider>
      <div className="tags">
        <ul className="tags__list">
          {tags.map((tag) => (
            <li className="tags__tag">
              {tag}
              <X
                className="tags__close-icon"
                size="16"
                onClick={() => {
                  setTags([...tags.filter((word) => word !== tag)]);
                }}
              />
            </li>
          ))}
        </ul>

        <div className="tags__form">
          <input
            className="tags__input"
            type="text"
            placeholder="Add a tag.."
            onKeyPress={(event) => {
              if (event.key === "Enter") {
                setTags([...tags, event.target.value]);
                event.target.value = "";
              }
            }}
            autofocus
          />
        </div>
      </div>
    </TagProvider>
  );
}

TagContext.js

import { useState, createContext } from "react";

export const TagContext = createContext();

const TagProvider = (props) => {
  const [valueTwo, setValueTwo] = useState([]);
  const [tags, setTags] = useState([]);

  return (
    <TagContext.Provider value={[valueTwo, setValueTwo, tags, setTags]}>
      {props.children}
    </TagContext.Provider>
  );
};

export default TagProvider;

标签: reactjsnpmsearchfilterreact-hooks

解决方案


我不知道你有什么context/TagContext,但通常情况下,一个提供者应该只使用一次,并且应该放置在包装将订阅该上下文的 Childs 中,并且你正在使用TagProviderMain.js、Tag.js和 Card.js,你应该只保留TagProviderMain.js 文件中的那个。移除额外的提供者后,接下来要做的更改是通过该提供者传递值,方法是在其上放置valueprop: <TagProvider value={[valueTwo, setValueTwo]}>。在这段代码中,我们传递了一个数组,该数组在第一个位置将具有函数,valueTwo而在第二个位置将具有setValueTwo函数。之后,提供者内部的任何组件(无论深度级别)都可以订阅该上下文并使用这些值。所以在 Tag.js 中,当你使用这段代码时:useContext(TagContext);它将解析为一个数组,该数组将包含您通过提供程序值传递的内容,并且该数组的形式为:[valueTwo, setValueTwo]

这些答案基于您应该拥有的内容,context/TagContext因此如果您也共享该代码会很好。


推荐阅读