为什么我的useEffect react函数在页面加载时运行,尽管我为其提供了第二个值数组

时间:2020-03-07 09:45:42

标签: javascript reactjs react-hooks use-effect use-state

为什么我的useEffect react函数在每次页面加载时都运行,尽管给了它第二个带有query变量的值数组?

useEffect( () => {
    getRecipes();
}, [query]);

不是仅当query状态变量更改时才运行吗?除了useEffect函数之外,我没有其他使用getRecipes函数的方法。

import React, {useEffect, useState} from 'react';
import './App.css';
import Recipes from './components/Recipes/Recipes';

const App = () => {

    // Constants
    const APP_ID                                = '111';
    const APP_KEY                               = '111'; 
    const [recipes, setRecipes]                 = useState([]);
    const [search, setSearch]                   = useState(''); 
    const [query, setQuery]                     = useState('');
    const [showRecipesList, setShowRecipesList] = useState(false);

    // Lets
    let recipesList                             = null; 

    // Functions
    useEffect( () => {
        getRecipes();
    }, [query]);

    // Get the recipie list by variables
    const getRecipes = async () => {
        const response = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}&from=0&to=3&calories=591-722&health=alcohol-free`); 
        const data     = await response.json(); 
        console.log(data.hits);
        setRecipes(data.hits);
    }

    // Update the search constant 
    const updateSearch = e => {
        console.log(e.target.value);
        setSearch(e.target.value);
    }

    const runQuery = e => {
        e.preventDefault();
        setQuery(search);
    }


    // List recipes if ready
    if (recipes.length) {
        console.log(recipes.length);
        recipesList = <Recipes recipesList={recipes} />
    }

    return (

        <div className="App">

            <form className='search-app' onSubmit={ runQuery }>
                <input 
                    type='text' 
                    className='search-bar' 
                    onChange={ updateSearch } 
                    value={search}/>
                <button 
                    type='submit'   
                    className='search-btn' > Search </button>
            </form>

            <div className='recipesList'>
                {recipesList}
            </div>

        </div>

    );

}

export default App;

此之后:https://www.youtube.com/watch?v=U9T6YkEDkMo

2 个答案:

答案 0 :(得分:2)

useEffectcomponentDidMount等效,因此它将在组件安装时运行一次,然后仅在依赖项数组中定义的一个依赖项发生更改时才重新运行。

如果仅当getRecipes()依赖项具有值时才想调用query,则可以像这样的条件调用它:

useEffect(() => {
  if(query) {
    getRecipes()
  }
}, [query])

此外,当您的useEffect调用的函数(getRecipes)声明为外部使用效果而在内部内部时,应该将函数声明移到useEffect内并添加适当的依赖关系,或者将函数包装在useCallback中并添加函数作为useEffect的依赖关系。

请参阅React docs,以了解为什么这很重要。

答案 1 :(得分:0)

UseEffect钩子工作等效于componentDidMount,componentDidUpdate和componentWillUnmount组合了React类组件的生命周期。但是在DOM.componentDidMount和useEffect的作用时间不同,在挂载后运行。但是useEffect在将油漆提交到屏幕之后而不是之前运行。这意味着如果您需要读取DOM,然后同步设置状态以创建新的UI,则会出现闪烁。useLayoutEffect的设计时间与componentDidMount相同。所以useLayoutEffect(fn,[])比useEffect(fn,[])更接近componentDidMount()-至少从时间角度来看。 这是否意味着我们应该改用useLayoutEffect? 可能不会。 如果确实要通过同步设置状态来避免该闪烁,请使用useLayoutEffect。但是由于这些情况很少见,因此您通常会希望使用useEffect。