回调函数的正确使用方法

7
目前,每次查询参数更新时,我的代码都会重新渲染。但是一旦我删除查询参数,就会收到一个警告:“React Hook useCallback has a missing dependency: 'query'. Either include it or remove the dependency array react-hooks/exhaustive-deps”。 我尝试在useEffect中定义我的getData函数,但我将getData用作useEffect之外的onclick函数。 我想要完成的目标是,在react hooks上最初获取文章,然后仅在提交时获取新数据,而不是在查询更新时获取,并且没有任何有关“查询”缺少依赖项的警告。 任何建议都会帮助极大。代码如下:
import React, { useState, useEffect, useCallback } from "react"
import axios from "axios"

const Home = () => {
  const [data, setData] = useState(null)
  const [query, setQuery] = useState("react hooks")

  const getData = useCallback(async () => {
    const response = await axios.get(
      `http://hn.algolia.com/api/v1/search?query=${query}`
    )
    setData(response.data)
  }, [query])

  useEffect(() => {
    getData()
  }, [getData])

  const handleChange = event => {
    event.preventDefault()
    setQuery(event.target.value)
  }

  return (
    <div>
      <input type='text' onChange={handleChange} value={query} />
      <button type='button' onClick={getData}>
        Submit
      </button>
      {data &&
        data.hits.map(item => (
          <div key={item.objectID}>
            {item.url && (
              <>
                <a href={item.url}>{item.title}</a>
                <div>{item.author}</div>
              </>
            )}
          </div>
        ))}
    </div>
  )
}

export default Home

1
如果你想要只在提交时运行getData,那么你不需要useEffect,但如果你使用它,你可以有一个提交状态,并且只有在submitting为true时才运行effect。 - azium
1
抱歉,我想最初获取关于React Hooks的文章,但只在提交时获取新数据,而不是在查询更新时获取。 - Rob Terrell
@azium,你提出的提交状态的唯一问题是我需要让useEffect最初运行,这样我才能在挂载时填充React Hooks文章。 - Rob Terrell
然后最初将提交状态设置为true。我可以立即为您撰写答案。 - azium
我能看看你是怎么做的吗?我遇到的提交状态问题是,数据仍然会随着查询的更新而更新。我真的很感激 @azium - Rob Terrell
1个回答

8
添加一个 `submitting` 状态,作为触发 axios 请求的条件。
  const [submitting, setSubmitting] = useState(true)
  const [data, setData] = useState(null)
  const [query, setQuery] = useState("react hooks")

  useEffect(() => {
    const getData = async () => {
      const response = await axios.get(
        `http://hn.algolia.com/api/v1/search?query=${query}`
      )
      setData(response.data)
      setSubmitting(false) // call is finished, set to false
    }

    // query can change, but don't actually trigger 
    // request unless submitting is true

    if (submitting) { // is true initially, and again when button is clicked
      getData()
    }
  }, [submitting, query])

  const handleChange = event => {
    event.preventDefault()
    setQuery(event.target.value)
  }

  const getData = () => setSubmitting(true)

如果您想使用useCallback,可以将其重构为以下代码:

  const [submitting, setSubmitting] = useState(true)
  const [data, setData] = useState(null)
  const [query, setQuery] = useState("react hooks")

  const getData = useCallback(async () => {
    const response = await axios.get(
      `http://hn.algolia.com/api/v1/search?query=${query}`
    )
    setData(response.data)
  }, [query])

  useEffect(() => {
    if (submitting) { // is true initially, and again when button is clicked
      getData().then(() => setSubmitting(false))
    }
  }, [submitting, getData])

  const handleChange = event => {
    event.preventDefault()
    setQuery(event.target.value)
  }

并在渲染中
<button type='button' onClick={() => setSubmitting(true)}>

似乎这个解决方案无法成功获取任何内容。控制台日志显示响应数据为未定义。 - Rob Terrell
这段代码不会改变你进行查询的方式。确保网络请求正确吗? - azium
1
哦,抱歉,我漏掉了异步关键字,请再试一次。 - azium
我发现问题出在异步请求之外的等待。这似乎解决了问题!谢谢@azium,现在更加清晰易懂了。 - Rob Terrell
1
更新了答案以符合您的问题,使用了 useCallback。 - azium
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接