ReactJS:React setState/useState 不会立即更新

ReactJS: React setState/useState does not update immediately

我正在构建一个美食食谱应用程序,我有一个即时自动过滤搜索结果,当用户键入任何字母时查询并获取数据。例如,对于字母“c”,它将显示成分中包含字母“c”的结果列表。一切似乎都工作正常,除了自动过滤器向后延迟一个字母,所以当用户键入“ch”或“c + 一个随机字母时它只显示包含字母“c”的结果".

我读了这个 link:https://linguinecode.com/post/why-react-setstate-usestate-does-not-update-immediatelyand 这有助于我定义为什么 React useState 不会立即更新,我认为解决方案是使用 React useEffect。我是学习 React 的新手,所以我很难将我的代码重构为在我的案例中使用 useEffect。如果有人启发我,我将不胜感激。谢谢大家!

这是我的演示:gif

这是我的代码:

// Recipes.js

export default function Recipes() {

  const [query, setQuery] = useState("")
  const [recipes, setRecipes] = useState([])
  const [alert, setAlert] = useState("")

  const APP_ID = "5b1b4741"
  const APP_KEY = "0325f7a61ac15027151b8060740d90f0"

  const url = `https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`    

  const getData = async () => {
    if (query !== "") {
      const result = await Axios.get(url)
      if (!result.data.more) {
        return setAlert("No food with such name")
      }
      console.log(result)
      setRecipes(result.data.hits)
      setQuery("")
      setAlert("")
    } else {
      setAlert("Please fill the form")
    }
  }
    
  const onChange = async e => {
    setQuery(e.target.value)
    if (query !== "") {
      const result = await Axios.get(url)
      console.log(result)
      setRecipes(result.data.hits)
    }
  }

  const onSubmit = e => {
    e.preventDefault()
    getData()
  };

  return (
    <div className="recipes">
      <div className="search-box">
        <h1>Your Recipe App</h1>

        <form onSubmit={onSubmit} className="search-form">
          {alert !== "" && <Alert alert={alert} />}

          <input
            type="text"
            name="query"
            onChange={onChange}
            value={query}
            placeholder="Search Food"
          />
          <input type="submit" value="Search" />
        </form>
        
        {query.length !== 0 && 
          <div className="search-result">
            {recipes.slice(0, 5).map((val) => {
              return (
                <a className="search-item" href={val.recipe.url} target="_blank" rel="noopener noreferrer">
                  <p>{val.recipe.label}</p>
                </a>
              ) 
            })}
          </div>
        }
      </div>

      <div className="recipes-card">
        {recipes !== [] &&
          recipes.map(recipe => <Recipe key={uuidv4()} recipe={recipe} />)}
      </div>
    </div>

// Recipe.js

const Recipe = ({ recipe }) => {
  const [show, setShow] = useState(false);
  const { label, image, url, ingredients } = recipe.recipe;

  return (
    <div className="recipe">
      <h2>{label}</h2>
      <img src={image} alt={label} />
      <a href={url} target="_blank" rel="noopener noreferrer">
        Go To Link
      </a>
      <button onClick={() => setShow(!show)}>Ingredients</button>
      {show && <RecipeDetails ingredients={ingredients} />}
    </div>
  )
}

export default Recipe
  const onChange = async e => {
    setQuery(e.target.value)
    if (query !== "") {
      const result = await Axios.get(url)
      console.log(result)
      setRecipes(result.data.hits)
    }
  }

您正在发送消息以设置 query 的新值,但随后 立即 使用旧值(函数已关闭)使您的Ajax请求。

任一:

  • 只需使用 e.target.value 而不是 query(不要忘记也移动计算 url 值的逻辑)。
  • 设置一个 useEffect 依赖于 query 的挂钩,其中包含我引用的第 3-7 行的代码。

你不是被迫使用useEffect:

export default function Recipes() {

  const [query, setQuery] = useState("")
  const [recipes, setRecipes] = useState([])
  const [alert, setAlert] = useState("")

  const APP_ID = "5b1b4741"
  const APP_KEY = "0325f7a61ac15027151b8060740d90f0"

  const baseUrl = `https://api.edamam.com/search`    

  const getData = async () => {
    if (query !== "") {
      const result = await Axios.get(baseUrl + `?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`)
      if (!result.data.more) {
        return setAlert("No food with such name")
      }
      console.log(result)
      setRecipes(result.data.hits)
      setQuery("")
      setAlert("")
    } else {
      setAlert("Please fill the form")
    }
  }
    
  const onChange = async e => {
    setQuery(e.target.value)
    if (query !== "") {
      const result = await Axios.get(baseUrl + `?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`)
      console.log(result)
      setRecipes(result.data.hits)
    }
  }

  const onSubmit = e => {
    e.preventDefault()
    getData()
  };

  return (
    <div className="recipes">
      <div className="search-box">
        <h1>Your Recipe App</h1>

        <form onSubmit={onSubmit} className="search-form">
          {alert !== "" && <Alert alert={alert} />}

          <input
            type="text"
            name="query"
            onChange={onChange}
            value={query}
            placeholder="Search Food"
          />
          <input type="submit" value="Search" />
        </form>
        
        {query.length !== 0 && 
          <div className="search-result">
            {recipes.slice(0, 5).map((val) => {
              return (
                <a className="search-item" href={val.recipe.url} target="_blank" rel="noopener noreferrer">
                  <p>{val.recipe.label}</p>
                </a>
              ) 
            })}
          </div>
        }
      </div>

      <div className="recipes-card">
        {recipes !== [] &&
          recipes.map(recipe => <Recipe key={uuidv4()} recipe={recipe} />)}
      </div>
    </div>