reactjs - useQuery 和 useEffect 用于简单搜索
问题描述
我有一个非常复杂的组件,现在我正在尝试实现用户可以键入的搜索并过滤结果。
// query
const GET_ACCOUNTS = gql`
query accounts{
accounts{
id
name
status
company{
id
name
}
}
}
`;
// get query
const { loading } = useQuery(GET_ACCOUNTS, {
fetchPolicy: "no-cache",
skip: userType !== 'OS_ADMIN',
onCompleted: setSearchResults
});
// example of query result (more than 1)
{
"accounts": [
{
"id": "5deed7df947204960f286010",
"name": "Acme Test Account",
"status": "active",
"company": {
"id": "5de84532ce5373afe23a05c8",
"name": "Acme Inc.",
"__typename": "Company"
},
"__typename": "Account"
},
]
}
// states
const [searchTerm, setSearchTerm] = useState('');
const [searchResults, setSearchResults] = useState([]);
// code to render
<FormControl fullWidth>
<InputLabel htmlFor="seach">Search for accounts</InputLabel>
<Input
id="search"
aria-describedby="Search for accounts"
startAdornment={<InputAdornment position="start"><SearchIcon /></InputAdornment>}
value={searchTerm}
onChange={handleChange}
/>
</FormControl>
{searchResults && searchResults.accounts &&
searchResults.accounts.map(c => {
return (
<>
<ListItem
dense
button
className={classnames({ [classes.selectedAccountContext]: c.id === accountContextId })}
key={c.id}
onClick={() => accountClicked(c.id)}
>
<ListItemText
primary={c.name}
secondary={
<>
<span>{c.company.name}</span>
<span className="d-flex align-items-center top-margin-tiny">
<Badge
color={c.status === 'active' ? "success" : "danger"}
style={{ marginBottom: 0 }}
>
{c.status.replace(/^\w/, c => c.toUpperCase())}
</Badge>
<span className='ml-auto'>
<SvgIcon><path d={mdiMapMarkerRadius} /></SvgIcon>
<SMARTCompanyIcon />
</span>
</span>
</>
}
/>
</ListItem>
</>
)
})
}
// useEffect
useEffect(() => {
if (searchTerm) {
const results = searchResults.accounts.filter((c => c.name.toLowerCase().includes(searchTerm)))
setSearchResults(results)
}
}, [searchTerm])
问题是当我开始在我的搜索字段中输入时,我正在查看我的searchResults
,当我输入一个字符时它会被过滤,但是当我输入下一个字符时它会中断。
TypeError: Cannot read property 'filter' of undefined
即使我输入了一个字母,它也不会在视图上呈现。
解决方案
根据您的数据, 的初始值searchResults
是带有accounts
键的字典。但是当你在useEffect
部件中更新它时,它会变成一个列表:
useEffect(() => {
if (searchTerm) {
const results = searchResults.accounts.filter((c => c.name.toLowerCase().includes(searchTerm)))
// This changes the value of searchResults to an array
setSearchResults(results)
}
}, [searchTerm])
在setSearchResults
内部调用时useEffect
,值searchResults
从对象变为数组:
由此:
搜索结果 = { 帐户:[ ... ] }
对此:
搜索结果 = [ ... ]
这就是为什么它TypeError: Cannot read property 'filter' of undefined
在第一次搜索后引发,因为不再有accounts
密钥了。
要解决这个问题,您需要在您的数据类型上保持一致searchResults
,最好首先将其设置为 List。您可以在以下onCompleted
部分执行此操作:
const { loading } = useQuery(GET_ACCOUNTS, {
fetchPolicy: "no-cache",
skip: userType !== 'OS_ADMIN',
onCompleted: (data) => setSearchResults(data.accounts || [])
});
请注意,我们设置searchResults
了该accounts
值。之后,您还需要访问方式searchResults
{searchResults &&
searchResults.map(c => {
return (
...renderhere
)
})
}
你的useEffect
会是这样的:
useEffect(() => {
if (searchTerm) {
const results = searchResults.filter((c => c.name.toLowerCase().includes(searchTerm)))
setSearchResults(results)
}
}, [searchTerm])
小费:
您可能需要重命名searchResults
为accounts
以使其更清晰。另请注意,在第一次搜索后,您的选项将仅限于以前的搜索结果,因此您可能还希望将所有帐户存储在不同的变量中:
const [allAccounts, setAllAccounts] = useState([])
const [searchedAccounts, setSearchedAccounts] = useState([])
// useQuery
const { loading } = useQuery(GET_ACCOUNTS, {
fetchPolicy: "no-cache",
skip: userType !== 'OS_ADMIN',
onCompleted: (data) => {
setAllAccounts(data.accounts || [])
setSearchedAccounts(data.accounts || [])
}
});
// useEffect
useEffect(() => {
if (searchTerm) {
// Notice we always search from allAccounts
const results = allAccounts.filter((c => c.name.toLowerCase().includes(searchTerm)))
setSearchedAccounts(results)
}
}, [searchTerm])
推荐阅读
- python - 基本 django 站点给出错误为“未找到:/nettrack/
- reactjs - 在 bootstrap-react-table-2 中创建/获取全局数据 ID
- python - 将天数转换为日期时间
- capl - linUpdateResponse 与输出 - LIN 模拟节点有何不同?
- tensorflow - 如何手动初始化 TF 1.x LSTMCell 和 dynamic_rnn
- c# - 通过列表值获取字典键
- excel-formula - Averageifs 使用索引匹配动态选择整列进行平均
- ios - 删除插入分组 UITableView 上方的空间
- python-3.x - 在 PyCharm 中导入文件 for UnitTest 教程
- tensorflow - 为什么 1x1 卷积层可用于神经网络回归中的特征减少?