与React中的useState,useEffect和useRef混淆

时间:2019-10-21 20:27:03

标签: reactjs react-hooks react-state

我的应用是配方搜索。我从API获得了一个搜索表单和一个提交按钮,以及配方结果。 我有查询状态变量(用useState()声明),我尝试使用搜索表单上的onSubmit函数对其进行更新。因此,我的想法是:有人在搜索栏中键入内容,然后提交查询。 MY onSubmit使用当前值并尝试设置查询。 问题是,我的查询总是延迟1个渲染。默认查询为“鸡肉”,因此,如果我输入“ cocoa”并单击“提交”,则API将为我提供鸡肉的结果,如果我在战后输入“ carrot”,则现在将获得“ cocoa”的结果。显然我错过了一些东西,因为我的状态跟不上变化。

还有一个额外的问题,如果发生这种情况是因为我没有在useEffect中调用getRecipes函数(相反,我只是提到了它)。如果我打电话给我,我会得到一个错误:

未捕获的TypeError:destroy不是函数  index.js:1375警告:无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要修复,请取消使用useEffect清理功能中的所有订阅和异步任务。

我的代码:

import React, { useEffect, useState, useRef } from "react";
import logo from "./logo.svg";
import Recipe from "./Recipe";
import "./App.css";

const App = () => {
  const APP_ID = "c49a2xxx";
  const APP_KEY = "0fbf56f642af60a29a73841f1fbdcxxx";
  const [recipes, setRecipes] = useState([]);
  //const [search, setSearch] = useState("");
  const [query, setQuery] = useState("chicken");
  const search = useRef();
  const exampleRequest = `https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`;
  useEffect(() => getRecipes, []);
  useEffect(() => getRecipes, [query]);
  const getRecipes = async () => {
    const response = await fetch(exampleRequest);
    const data = await response.json();
    setRecipes(data.hits);
  };
  const submitSearch = (e) => {
    e.preventDefault();
    setQuery(search.current.value);
  };
  return (
    <div className="App">
      <form onSubmit={submitSearch}>
        <input type="text" ref={search} />
        <button type="submit">Search</button>
      </form>{" "}
      {recipes.map((recipe, key) => (
        <Recipe
          key={key}
          title={recipe.recipe.label}
          calories={recipe.recipe.calories}
          img={recipe.recipe.image}
        />
      ))}
    </div>
  );
};

export default App;

1 个答案:

答案 0 :(得分:1)

我认为内存泄漏错误可能是由这两种影响引起的。

// Declared outside the component since it'll never change
const APP_ID = 'c49a2xxx';
const APP_KEY = '0fbf56f642af60a29a73841f1fbdcxxx';

const App = () => {
  const [recipes, setRecipes] = useState([]);
  const [query, setQuery] = useState('chicken');
  const search = useRef();

  // useEffect(() => getRecipes, []); You don't need two effects that does the same task
  useEffect(() => {
    const getRecipes = async () => {
      // request url with params declared inside the function
      // to make sure you're using the updated state variable
      const exampleRequest = `https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`;
      const response = await fetch(exampleRequest);
      const data = await response.json();
      setRecipes(data.hits);
    };

    getRecipes();
  }, [query, APP_ID, APP_KEY]);

  const submitSearch = e => {
    e.preventDefault();
    setQuery(search.current.value);
  };

  return (
    <div className="App">
      <form onSubmit={submitSearch}>
        <input type="text" ref={search} />
        <button type="submit">Search</button>
      </form>
      {recipes.map((recipe, key) => (
        <Recipe
          key={key}
          title={recipe.recipe.label}
          calories={recipe.recipe.calories}
          img={recipe.recipe.image}
        />
      ))}
    </div>
  );
};

如果您想了解有关中止中断获取的更多信息,这是我发现有用的文章。

https://itnext.io/how-you-can-abort-fetch-request-on-a-flight-830a639b9b92

相关问题