每次渲染后将调用哪个useEffect?

时间:2020-08-01 13:33:33

标签: javascript reactjs async-await use-effect react-functional-component

我是React的初学者,遇到了一些问题。我对此代码有几个疑问。

  1. 每次渲染后将调用哪个UseEffect?

  2. 为什么和如何调用console.log()13次?(请在下面的屏幕截图中找到)

  3. 为什么直到在搜索栏中输入内容后,浏览器中才会显示获取的数据?

    App.js

     import React, { useEffect } from "react";
     import { useState } from "react";
     import axios from "axios";
    
     function App() {
       const [monster, setMonster] = useState([]);
       const [searchName, setName] = useState("");
       const [filteredMonster, setFilter] = useState([]);
    
       useEffect(() => {
          async function fetchData() {
            await axios.get(
               "https://jsonplaceholder.typicode.com/users"
            ).then((resp)=>{
               setMonster(resp.data);
            })
            console.log(monster);
          }
    
          fetchData();
       }, []);
    
       useEffect(()=>{
          const mons = monster;
          setFilter(mons.filter(mon =>
             mon.name.toLowerCase().includes(searchName.toLowerCase())
          ));
       }, [searchName]);
    
       function changeName(event) {
          setName(event.target.value);
       }
    
       console.log(monster);
    
       const cunter = useRef(0);
       return (
          <div className="App">
             <form>
                <input
                   type="search"
                   name="searchName"
                   value={searchName}
                   onChange={changeName}
                />
             </form>
    
            {cunter.current++}
    
             {filteredMonster&&filteredMonster.map((item, index) => (
                <p key={index}>{item.name}</p>
             ))}
    
             {monster&&!filteredMonster&&monster.map((item, index) => (
                <p key={index}>{item.name}</p>
              ))}
          </div>
       );
     }
    
     export default App;
    

App

Cunter

2 个答案:

答案 0 :(得分:0)

请尝试一下。 fetchData()将仅运行1,searchName将在您在屏幕上键入的次数相同。

提示:为防止这种情况。在用户完成键入后仅添加一次渲染,而不是用户按键盘键的N次渲染,请添加timeoutdelay。

import React, { useEffect } from "react";
import { useState } from "react";
import axios from "axios";

const URL = "https://jsonplaceholder.typicode.com/users"

function App() {
    const [monster, setMonster] = useState([]);
    const [searchName, setName] = useState("");
    const [filteredMonster, setFilter] = useState([]);

    useEffect(() => {
        async function fetchData() {
            await axios.get(URL).then((resp) => {
                setMonster(resp.data);
            })
            console.log(monster);
        }

        fetchData();
    }, []);

    useEffect(() => {
        if (monster.length > 0) {
            const filter = mons.filter(({name}) =>
                name.toLowerCase().includes(searchName.toLowerCase()));
            setFilter(filter);
        }

    }, [searchName]);

    function changeName(event) {
        setName(event.target.value);
    }

    console.log(JSON.stringify(monster));

    return (
        <div className="App">
            <form>
                <input
                    type="search"
                    name="searchName"
                    value={searchName}
                    onKeyUp={(e) => changeName(e)}
                />
            </form>

            {monster.length > 0 &&
                <div>{JSON.stringify(monster)}</div>
            }

            {filteredMonster && filteredMonster.map((item, index) => (
                <p key={index}>{item.name}</p>
            ))}

            {monster && !filteredMonster && monster.map((item, index) => (
                <p key={index}>{item.name}</p>
            ))}
        </div>
    );
}

export default App;

这正在使用Reducer,删除了状态的使用。


import React, { useEffect, useReducer } from "react";
import axios from "axios";

const URL = "https://jsonplaceholder.typicode.com/users"

const reducer = (state, action) => {
    switch(action.type){
        case 'FETCH_DATA':
            return {
                ...state,
                monster: action.monster,
                name: "",
            }
        case 'SEARCH_MONSTER':
            return {
                ...state,
                name: action.name,
            }
        case 'FILTER_MONSTER':
            const filter = state.monster.filter(({name}) =>
                name.toLowerCase().includes(searchName.toLowerCase()));
            return {
                ...state,
                filteredMonster: filter,
                name: state.name,
            }
    }
};

function App() {

    const [state, dispatch] = useReducer(reducer, {
        monster: [],
        filteredMonster: [],
        name: '',
    });

    useEffect(() => {
        async function fetchData() {
            await axios.get(URL).then((resp) => {
                dispatch({ type: 'FETCH_DATA', monster: resp.data});
            })
            console.log(monster);
        }
        fetchData();
    }, []);

    useEffect(() => {
        if (monster.length > 0)  dispatch({ type: 'FILTER_MONSTER'});
    }, [stat.name]);

    console.log(JSON.stringify(monster));

    return (
        <div className="App">
            <form>
                <input
                    type="search"
                    name="searchName"
                    value={state.name}
                    onKeyUp={(e) => dispatch({ type: 'SEARCH_MONSTER', name: e.target.value })}
                />
            </form>

            {state.monster.length > 0 &&
                <div>{JSON.stringify(monster)}</div>
            }

            {state.filteredMonster && state.filteredMonster.map((item, index) => (
                <p key={index}>{item.name}</p>
            ))}

            {state.monster && !state.filteredMonster && monster.map((item, index) => (
                <p key={index}>{item.name}</p>
            ))}
        </div>
    );
}

export default App;

答案 1 :(得分:0)

1。每次渲染后将调用哪个UseEffect?

答案:根据react official doc useEffect确实关心3个生命周期方法,即componentDidMount componentDidUpdatecomponentWillUnmount。因此,无论您有多少useEffect,所有效果挂钩都将在componentMount首次执行时执行。但是useEffect仅在依赖项获得更新时才会进一步执行,否则它将忽略

2。为什么和如何调用console.log()13次?

答案::我尝试重现13次重渲染,但无法做到。但是,是的,它要重新渲染多次,因为在每个Keystore的第二个useEffect中,状态都在更新,并且由于该组件要多次渲染。

它发生了这样的事情

changeName()→setName()→useEffect()→setFilter()→(在重复相同步骤的每个密钥库上)→... loop

您可以尝试debouncethrottling,这可以帮助您避免连续的Keystore命中,从而避免重新渲染而造成的损失。

代替使用 console.log ,有一种黑客可以知道重新渲染的次数

在组件中声明以下代码

const cunter = useRef(0);

,然后在return块中添加{cunter.current++},您可以看到组件实际重新渲染了多少次

3。为什么直到我在搜索栏中输入某些内容后,浏览器中才会显示获取的数据?

这是因为在您的条件下,您检查!filteredMonster,其中filteredMonster是一个数组,而!filteredMonster将总是返回false,而尝试使用数组length属性

filteredMonster.length === 0

{monster && !filteredMonster && monster.map((item, index) => (
     <p key={index}>{item.name}</p>
))}

{(monster && filteredMonster.length === 0) && monster.map((item, index) => (
         <p key={index}>{item.name}</p>
))}