Какой useEffect будет вызываться после каждого рендера? - PullRequest
0 голосов
/ 01 августа 2020

Я новичок в React и столкнулся с какой-то проблемой. У меня есть несколько вопросов по этому коду.

  1. Какой UseEffect будет вызываться после каждого рендеринга?

  2. Почему и как console.log () вызывается 13 раз? (См. снимок экрана ниже)

  3. Почему полученные данные не отображаются в браузере, пока я не наберу что-то в строке поиска?

    Приложение. 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 голосов
/ 01 августа 2020

1. Какой UseEffect будет вызываться после каждого рендеринга?

Ответ: Согласно официальному ответу do c useEffect заботится о 3 методах жизненного цикла а именно componentDidMount componentDidUpdate и componentWillUnmount. Итак, независимо от того, сколько useEffect у вас есть, все перехватчики эффектов будут выполняться при componentMount в первый раз. Но useEffect будет выполняться дальше, только когда зависимость получит обновления, иначе он проигнорирует

2. Почему и как console.log () вызывается 13 раз?

Ответ: Я пытался воспроизвести повторную визуализацию 13 раз, но не могу этого сделать. Но да, он перерисовывается несколько раз, потому что во втором useEffect в каждом хранилище ключей состояние обновляется, и из-за того, что этот компонент перерисовывается несколько раз.

происходит что-то вроде этого

changeName () → setName () → useEffect () → setFilter () → (на каждом хранилище ключей, повторяющем один и тот же шаг) → ... l oop

вы можете попробовать debounce или throttling, которые могут помочь вам Избегайте непрерывного обращения к хранилищу ключей, из-за которого никакая повторная отрисовка не может значительно сократить

Вместо использования console.log , есть хак, чтобы узнать количество повторных отрисовок

объявите приведенный ниже код в компоненте

const cunter = useRef(0);

, а затем в блоке возврата добавьте {cunter.current++}, с помощью этого вы можете увидеть, сколько раз ваш компонент фактически перерисовывает

3. Почему полученные данные не отображаются в браузере до тех пор, пока я не наберу что-то в строке поиска?

Это потому, что в вашем состоянии ваша проверка !filteredMonster, где filteredMonster - массив, а !filteredMonster всегда будет возвращать false вместо этого попробуйте Array length properties

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>
))}
0 голосов
/ 01 августа 2020

попробуйте это, пожалуйста. fetchData () будет запускаться только 1, searchName будет запускаться столько раз, сколько вы вводите на экране.

СОВЕТ: Во избежание этого. добавить задержку тайм-аута после того, как пользователь закончит ввод, чтобы отобразить только один раз, а не N раз, когда пользователь нажимает клавишу клавиатуры.

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;

...