我有以下代码:
import React, { useState, useEffect } from "react"
function callSearchApi(userName: string, searchOptions: SearchOptions, searchQuery: string): Promise<SearchResult>{
return new Promise((resolve, reject) => {
const searchResult =
searchOptions.fooOption
? ["Foo 1", "Foo 2", "Foo 3"]
: ["Bar 1", "Bar 2"]
setTimeout(()=>resolve(searchResult), 3000)
})
}
type SearchOptions = {
fooOption: boolean
}
type SearchResult = string[]
export type SearchPageProps = {
userName: string
}
export function SearchPage(props: SearchPageProps) {
const [isSearching, setIsSearching] = useState<boolean>(false)
const [searchResult, setSearchResult] = useState<SearchResult>([])
const [searchOptions, setSearchOptions] = useState<SearchOptions>({fooOption: false})
const [searchQuery, setSearchQuery] = useState<string>("")
const [lastSearchButtonClickTimestamp, setLastSearchButtonClickTimestamp] = useState<number>(Date.now())
// ####################
useEffect(() => {
setIsSearching(true)
setSearchResult([])
const doSearch = () => callSearchApi(props.userName, searchOptions, searchQuery)
doSearch().then(newSearchResult => {
setSearchResult(newSearchResult)
setIsSearching(false)
}).catch(error => {
console.log(error)
setIsSearching(false)
})
}, [lastSearchButtonClickTimestamp])
// ####################
const handleSearchButtonClick = () => {
setLastSearchButtonClickTimestamp(Date.now())
}
return (
<div>
<div>
<label>
<input
type="checkbox"
checked={searchOptions.fooOption}
onChange={ev => setSearchOptions({fooOption: ev.target.checked})}
/>
Foo Option
</label>
</div>
<div>
<input
type="text"
value={searchQuery}
placeholder="Search Query"
onChange={ev => setSearchQuery(ev.target.value)}
/>
</div>
<div>
<button onClick={handleSearchButtonClick} disabled={isSearching}>
{isSearching ? "searching..." : "Search"}
</button>
</div>
<hr/>
<div>
<label>Search Result: </label>
<input
type="text"
readOnly={true}
value={searchResult}
/>
</div>
</div>
)
}
export default SearchPage
参见this Codesandbox。
代码工作正常。我可以在文本字段中更改搜索查询并单击选项复选框。一旦我准备好了,我可以点击“搜索”按钮,只有这样,副作用才发生,获取数据。
现在,问题是编译器会抱怨:
React Hook useEffect缺少依赖项:'props.user. loginName'、'searchFilter'和' searchQuery'。包括它们或删除依赖项数组。[react-hooks/extive-deps]
但是,如果我将props.user.loginName
、searchFilter
和searchQuery
添加到依赖项列表中,那么每当我单击复选框或在文本字段中键入单个字符时,就会触发副作用。
我确实理解钩子依赖的概念,但我不知道如何先输入一些数据,然后只用一个按钮点击触发副作用。
这方面的最佳做法是什么?我读过https://reactjs.org/docs/hooks-effect.html和https://www.robinwieruch.de/react-hooks-fetch-data,但找不到任何关于我问题的例子。
更新1:
我还提出了this solution,它看起来像:
type DoSearch = {
call: ()=>Promise<SearchResult>
}
export function SearchPage(props: SearchPageProps) {
const [isSearching, setIsSearching] = useState<boolean>(false)
const [searchResult, setSearchResult] = useState<SearchResult>([])
const [searchOptions, setSearchOptions] = useState<SearchOptions>({fooOption: false})
const [searchQuery, setSearchQuery] = useState<string>("")
const [doSearch, setDoSearch] = useState<DoSearch>()
// ####################
useEffect(() => {
if(doSearch !==undefined){
setIsSearching(true)
setSearchResult([])
doSearch.call().then(newSearchResult => {
setSearchResult(newSearchResult)
setIsSearching(false)
}).catch(error => {
console.log(error)
setIsSearching(false)
})
}
}, [doSearch])
// ####################
const handleSearchButtonClick = () => {
setDoSearch({call: () => callSearchApi(props.userName, searchOptions, searchQuery)})
}
return (<div>...</div>)
}
现在,实际的函数是唯一工作正常的依赖项,编译器也很高兴。然而,我不喜欢的是,我需要具有call
属性的 Package 器对象。如果我想直接传递一个箭头函数给状态,这不会像预期的那样工作,例如:
const [doSearch, setDoSearch] = useState<()=>Promise<SearchResult>>()
...
setDoSearch(() => callSearchApi(props.userName, searchOptions, searchQuery))
doSearch
没有设置为箭头函数,但callSearchApi
会立即执行。有人知道为什么吗?
4条答案
按热度按时间agyaoht71#
您可以从效果中删除
setIsSearching(true)
,并在单击按钮时将其分开。然后,你可以修改你的
useEffect
语句,如下所示:这将实现你正在寻找的东西。另一种方法是禁用
react-hooks/exhaustive-deps
规则。如果你只需要在点击按钮时触发fetch,我只需要使用一个函数。
useEffect
是有用的,例如,当你有一个过滤器列表(切换),你想每次切换一个过滤器(想象一个电子商务)进行提取。这是一个幼稚的例子,但它说明了一点:8mmmxcuj2#
这就是useEffect应该是这样的。
props.userName
在依赖列表中是有意义的,因为我们肯定希望在userName更改时获取新数据。searchOptions
和searchQuery
当你遇到这种情况时,最好使用reducer,所以你只需要调度action ==>searchOptions
,searchQuery
就不会在userEffect
里面了。这篇文章从丹阿布拉莫夫提供了深入的解释,他们简单的例子实现它我用
useReducer
快速转换你的例子,请看一下Codesandbox for that
h9vpoimq3#
使用最新的React,你可以简单地用途:
定义所有依赖项并使用if语句检查可用性:
bttbmeg04#
副作用不是为了这个。但是如果你想在变量发生变化时执行useEffect,你可以把它放在依赖数组中。
示例
希望这个能帮上忙