英文:
What's the best practice for debounce on search changes and instant fetch on page changes with useState and useEffect in React?
问题
I'm having two state variables, page and search, and want to refetch data every time one of these are changed,
For search change I want to do debounce, and for page changes need to fetch instantly.
const [page, setPage] = useState()
const [search, setSearch] = useState();
const fetch = () => {
   axios.get("", {search, page}) // nvm the syntax
}
useEffect(()=>{
   const timer = setTimeout(()=>{ fetch() }, 3000)
   return () => { clearTimeout(timer) }
}, [search])
useEffect(()=>{
   fetch();
}, [page])
Unfortunately I'm getting eslint exhaustive deps warning here, if I fix these warnings, then fetch is called twice on change, could you please explain what's the correct way/best practice to tackle this? Thanks!
<details>
<summary>英文:</summary>
I'm having two state variables, `page` and `search`, and want to refetch data every time one of these are changed, 
For search change I want to do debounce, and for page changes need to fetch instantly.
```ts
const [page, setPage] = useState()
const [search, setSearch] = useState();
const fetch = () => {
   axios.get("", {search, page}) // nvm the syntax
}
useEffect(()=>{
   const timer = setTimeout(()=>{ fetch() }, 3000)
   return () => { clearTimeout(timer) }
}, [search])
useEffect(()=>{
   fetch();
}, [page])
Unfortunately I'm getting eslint exhaustive deps warning here, if I fix these warnings, then fetch is called twice on change, could you please explain what's the correct way/best practice to tackle this? Thanks!
答案1
得分: 2
你可以编写一个useDebouncedValue函数 -
const { useEffect, useState } = React
function useDebouncedValue(value, delay) {
  const [state, setState] = useState(value)
  useEffect(
    () => {
      const t = setTimeout(setState, delay, value)
      return () => { clearTimeout(t) }
    },
    [value, delay]
  )
  return state
}
function App() {
  const [foo, setFoo] = useState("hello")
  const debouncedFoo = useDebouncedValue(foo, 1000)
  return <div>
    <input onChange={e => setFoo(e.target.value)} value={foo} />
    debounced: {debouncedFoo}
  </div>
}
ReactDOM.createRoot(document.querySelector("#app")).render(<App />)
在你的组件中使用它可能会像这样 -
const [page, setPage] = useState()
const [search, setSearch] = useState()
const debouncedSearch = useDebouncedValue(search, 3000)
useEffect(
  () => {
    axios
      .get("", {search: debouncedSearch, page})
      .then(setResults)
      .catch(console.error)
  },
  [page, debouncedSearch]
)
英文:
You could write a useDebouncedValue -
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const { useEffect, useState } = React
function useDebouncedValue(value, delay) {
  const [state, setState] = useState(value)
  useEffect(
    () => {
      const t = setTimeout(setState, delay, value)
      return () => { clearTimeout(t) }
    },
    [value, delay]
  )
  return state
}
function App() {
  const [foo, setFoo] = useState("hello")
  const debouncedFoo = useDebouncedValue(foo, 1000)
  return <div>
    <input onChange={e => setFoo(e.target.value)} value={foo} />
    debounced: {debouncedFoo}
  </div>
}
ReactDOM.createRoot(document.querySelector("#app")).render(<App />)
<!-- language: lang-html -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
<!-- end snippet -->
Using it in your component might look something like this -
const [page, setPage] = useState()
const [search, setSearch] = useState()
const debouncedSearch = useDebouncedValue(search, 3000)
useEffect(
  () => {
    axios
      .get("", {search: debouncedSearch, page})
      .then(setResults)
      .catch(console.error)
  },
  [page, debouncedSearch])
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论