我想做的是我想从API获取员工列表,将其保存在状态中,然后按员工姓名进行“实时”搜索。
我苦恼的是我无法使用过滤后的数组更新状态。当我开始在搜索字段中输入内容时,员工会进行过滤,但是一旦删除了一些字母,就什么都不会改变。
如果我的.map()不是状态,而是包含过滤数组的变量,则一切正常。这在某种程度上与状态和状态更新有关。
这是我的代码:
import "./App.css";
import React, { useState, useEffect } from "react";
import styled from "styled-components";
const Container = styled.div`
width: 1280px;
max-width: 100%;
margin: 0 auto;
th {
text-align: left;
padding: 10px;
background: #f5f5f5;
cursor: pointer;
:hover {
background: #ddd;
}
}
td {
border-bottom: 1px solid #f5f5f5;
padding: 5px;
}
`;
const TopHeader = styled.div`
display: flex;
justify-content: space-between;
padding: 20px;
input {
width: 400px;
padding: 10px;
}
`;
function App() {
const [employees, updateEmployees] = useState([]);
if (employees == 0) {
document.title = "Loading...";
}
useEffect(() => {
fetch("http://dummy.restapiexample.com/api/v1/employees")
.then(res => res.json())
.then(result => {
updateEmployees(result.data);
document.title = `Total: ${result.data.length} `;
});
}, []);
const [searchValue, updateSearch] = useState("");
const filteredEmpl = employees.filter(empl => {
return empl.employee_name.toLowerCase().includes(searchValue.toLowerCase());
});
const handleSearch = e => {
updateSearch(e.target.value);
updateEmployees(filteredEmpl);
};
return (
<Container>
<TopHeader>
<div>
Total employees: <strong>{employees.length}</strong> Filtered
employees: <strong>{filteredEmpl.length}</strong>
</div>
<div>
<input
type="text"
onChange={handleSearch}
value={searchValue}
placeholder="search"
/>
</div>
</TopHeader>
<table style={{ width: "100%" }}>
<thead>
<tr>
<th>id</th>
<th>Employee name</th>
<th>Employee salary</th>
<th>Employee age</th>
</tr>
</thead>
<tbody>
{employees.map(employee => (
<tr key={employee.id}>
<td>{employee.id}</td>
<td>{employee.employee_name}</td>
<td>{employee.employee_salary}</td>
<td>{employee.employee_age}</td>
</tr>
))}
</tbody>
</table>
</Container>
);
}
export default App;
有什么想法吗?
答案 0 :(得分:0)
问题在于搜索词在这里过时了
const handleSearch = e => {
updateSearch(e.target.value);
updateEmployees(filteredEmpl);
};
呼叫updateEmployees
时。每次进行搜索时,您还将替换从api调用中获得的结果。无需将搜索字词设置为陈述,而是这样做:
const [searchResult, updateSearch] = useState([]);
const filterEmpl = useCallback((searchTerm) => {
return employees.filter(({employee_name}) => {
return employee_name.toLowerCase().includes(searchTerm.toLowerCase());
})
}, [employees]);
const handleSearch = useCallback(({target}) => {
const filteredEmpl = filterEmpl(target.value)
updateSearch(filteredEmpl);
}, [filterEmpl]);
答案 1 :(得分:0)
您不需要将筛选出的员工存储到状态变量中。每次更新searchValue
或employees
(使用useMemo
)时,您只需要从原始员工那里进行计算即可。
顺便说一句,最好像上面一样将标题管理成自己的效果。
const [employees, updateEmployees] = useState([]);
const [searchValue, updateSearch] = useState("");
useEffect(() => {
fetch("http://dummy.restapiexample.com/api/v1/employees")
.then(res => res.json())
.then(result => updateEmployees(result.data));
}, []);
useEffect(() {
document.title = !employees.length ? "Loading..." : `Total: ${employees.length} `
}, [employees]);
const filteredEmpl = useMemo(() => {
if (!searchValue) return employees;
return employees.filter(empl =>
empl.employee_name.toLowerCase().includes(searchValue.toLowerCase())
);
}, [employees, searchValue]);
const handleSearch = e => updateSearch(e.target.value);
如果要对一组员工进行排序,可以这样做
const filteredEmpl = useMemo(() => {
const sortFn = (empl1, empl2) => {...};
const filterFn = empl =>
empl.employee_name.toLowerCase().includes(searchValue.toLowerCase());
if (!searchValue) {
return [...employees].sort(sortFn);
} else {
return employees.filter(filterFn).sort(sortFn);
}
}, [employees, searchValue]);
如果排序条件可以由用户(使用输入)更新,则需要将排序条件存储到新的状态变量中。
答案 2 :(得分:0)
我通过更改几个变量名并对代码进行了一些调整,并添加了过滤器功能。我希望这有帮助。如果您在此问题上需要任何进一步的帮助,请告诉我。干杯!
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import "./App.css";
const Container = styled.div`
width: 1280px;
max-width: 100%;
margin: 0 auto;
th {
text-align: left;
padding: 10px;
background: #f5f5f5;
cursor: pointer;
:hover {
background: #ddd;
}
}
td {
border-bottom: 1px solid #f5f5f5;
padding: 5px;
}
`;
const TopHeader = styled.div`
display: flex;
justify-content: space-between;
padding: 20px;
input {
width: 400px;
padding: 10px;
}
`;
const Loading = styled.div`
display: flex;
text-align: 'center';
padding: 20px;
font-size: 2em;
font-weight: 300;
`;
const App = () => {
const [employees, setEmployees] = useState([]); // Change variable name from updateEmployees to setEmployees
const [searchValue, setSearchValue] = useState(""); // changed variable name from updateSearch to setSearchValue
const [employeesTotal, setEmployeesTotal] = useState(0); // Add a new state to handle intial employees total
// Renamed employees variable to employeesTotal
if (employeesTotal) {
document.title = "Loading...";
}
useEffect(() => {
fetch("http://dummy.restapiexample.com/api/v1/employees")
.then(res => res.json())
.then(result => {
setEmployees(result.data);
setEmployeesLength(result.data.length);
document.title = `Total: ${result.data.length} `; // Why though?
});
}, []);
const handleSearch = e => {
setSearchValue(e.target.value);
};
const filterDocument = doc => {
const employeeName = doc.employee_name.toLowerCase() || '';
return employeeName.includes(searchValue.toLowerCase());
};
// Check if employees array contains data, if it does, display content, otherwise show loading
return (
employeesTotal ? (
<Container>
<TopHeader>
<div>
Total employees: <strong>{employeesTotal}</strong> Filtered employees: <strong>{employees.length}</strong>
</div>
<div>
<input
type="text"
onChange={handleSearch}
value={searchValue}
placeholder="search"
/>
</div>
</TopHeader>
<table style={{ width: "100%" }}>
<thead>
<tr>
<th>id</th>
<th>Employee name</th>
<th>Employee salary</th>
<th>Employee age</th>
</tr>
</thead>
<tbody>
{/** Add filterDocument to filter function on employee array before calling its map funtion */}
{employees.filter(filterDocument).map(employee => (
<tr key={employee.id}>
<td>{employee.id}</td>
<td>{employee.employee_name}</td>
<td>{employee.employee_salary}</td>
<td>{employee.employee_age}</td>
</tr>
))}
</tbody>
</table>
</Container>
) : (
<Loading>Loading...</Loading>
)
);
}
export default App;