reactjs - 使用 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}>
+
</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;
解决方案
我不知道你有什么context/TagContext
,但通常情况下,一个提供者应该只使用一次,并且应该放置在包装将订阅该上下文的 Childs 中,并且你正在使用TagProvider
Main.js、Tag.js和 Card.js,你应该只保留TagProvider
Main.js 文件中的那个。移除额外的提供者后,接下来要做的更改是通过该提供者传递值,方法是在其上放置value
prop: <TagProvider value={[valueTwo, setValueTwo]}>
。在这段代码中,我们传递了一个数组,该数组在第一个位置将具有函数,valueTwo
而在第二个位置将具有setValueTwo
函数。之后,提供者内部的任何组件(无论深度级别)都可以订阅该上下文并使用这些值。所以在 Tag.js 中,当你使用这段代码时:useContext(TagContext);
它将解析为一个数组,该数组将包含您通过提供程序值传递的内容,并且该数组的形式为:[valueTwo, setValueTwo]
。
这些答案基于您应该拥有的内容,context/TagContext
因此如果您也共享该代码会很好。
推荐阅读
- laravel - Mapper 使用 Laravel 和 Elasticsearch 解析异常
- svg - 复制 svg 动画
- c# - 如何为声明创建自定义参数绑定?
- mysql - 有没有办法用特定的部分更新多个列?
- mysql - Magento 上的 MySQL 关闭问题
- laravel - 安装 Laravel DataTables Mongodb 插件
- android - 如何制作弹窗活动?
- javascript - 在 ng build --prod 期间无法解析验证指令中的所有参数
- ios - 从 Firebase 数据库中检索聊天消息列表时应用程序崩溃
- windows - Windows 资源管理器中的 FTP 列表命令输出视图格式不正确