UseEffect работает при монтировании, вызывая ошибку и пустой объект

Я продолжаю получать пустой элемент списка аватаров, когда я нажимаю «Добавить» в первый раз, а затем после этого соответствующий элемент отображается после второго щелчка. Если я добавлю новый URL-адрес и щелкну третий раз, элемент не появится до четвертого щелчка. Скорее всего, я делаю что-то не так со своими значениями useEffect и состояния.

import React, { useState, useEffect } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import List from '@material-ui/core/List';
import Divider from '@material-ui/core/Divider';
import AvatarListItem from './AvatarListItem';
import AddIcon from '@material-ui/icons/Add';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import axios from 'axios';

const useStyles = makeStyles((theme) => ({
    root: {
        display: 'flex',
        justifyContent: 'space-between',
        flexDirection: 'column',
        flexWrap: 'wrap',
        backgroundColor: theme.palette.background.paper,
    },

    inline: {
        display: 'inline',
    },
    formControl: {
        width: '100%',
        margin: theme.spacing(1),
        marginBottom: '50px',
        minWidth: 120,
    },
    extendedIcon: {
        margin: '10px',
        marginRight: theme.spacing(1),
    },
}));

export default function AvatarList() {
    const classes = useStyles();
    const [url, setUrl] = useState('');
    const [itemDetails, setItemDetails] = useState({});
    const [items, setItems] = useState([]);
    const [search, setSearch] = useState('');

    useEffect(() => {
        const fetchData = async () => {
            const result = await axios(
                `http://127.0.0.1:5000/api/resources/products?url=${url}`,
            )
            setItemDetails(result.data[0]);
        }
        fetchData()
    }, [search])


    const addItem = (itemDetails) => {
        const newItems = [...items, itemDetails];
        setItems(newItems);
    };

    let handleSubmit = (e) => {
        e.preventDefault();
        console.info(itemDetails);
        addItem(itemDetails);
    };

    let removeItem = (index) => {
        const newItems = [...items];
        newItems.splice(index, 1);
        setItems(newItems);
    };


    return (
        <div>
            <form className = {classes.formControl} onSubmit = {e => handleSubmit(e)}>
                <TextField id = "outlined-basic" label = "Amazon Url" variant = "outlined" name='newItem' onChange = {e => setUrl(e.target.value)} value = {url} />
                <Button variant = "contained" color = "primary" type = "submit" value = "Submit" onClick = {() => setSearch(url)}>
                    <AddIcon className = {classes.extendedIcon} />
                </Button>
            </form>


            <List className = {classes.root}>
                {items.map((item, index) => (
                    <>
                        <AvatarListItem
                            itemDetails = {item}
                            key = {index}
                            index = {index}
                            removeItem = {removeItem}
                        />
                        <Divider variant = "middle" component = "li" />
                    </>
                ))}
            </List>
        </div >
    );
}

Вы проверили свой useEffect? он получает новые данные только при изменении значения search. это ваше намерение? или вы хотите получать данные для каждого изменения значения item?

Hadi KAR 26.12.2020 02:59

я хотел бы получать данные каждый раз, когда пользователь нажимает кнопку добавления, и добавлять эти данные в список элементов

nickswink 26.12.2020 03:07
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
2
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Лучшим подходом может быть использование исключительно обратного вызова onSubmit вместо использования useEffect, который может запускаться чаще, чем необходимо. Кроме того, не похоже, что вам вообще нужно использовать состояние search или itemDetails.

import React, { useState, useEffect } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import List from '@material-ui/core/List';
import Divider from '@material-ui/core/Divider';
import AvatarListItem from './AvatarListItem';
import AddIcon from '@material-ui/icons/Add';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
import axios from 'axios';

const useStyles = makeStyles((theme) => ({
    root: {
        display: 'flex',
        justifyContent: 'space-between',
        flexDirection: 'column',
        flexWrap: 'wrap',
        backgroundColor: theme.palette.background.paper,
    },

    inline: {
        display: 'inline',
    },
    formControl: {
        width: '100%',
        margin: theme.spacing(1),
        marginBottom: '50px',
        minWidth: 120,
    },
    extendedIcon: {
        margin: '10px',
        marginRight: theme.spacing(1),
    },
}));

export default function AvatarList() {
    const classes = useStyles();
    const [url, setUrl] = useState('');
    const [items, setItems] = useState([]);


    const addItem = (itemDetails) => {
        const newItems = [...items, itemDetails];
        setItems(newItems);
    };

    let handleSubmit = async (e) => {
        e.preventDefault();
        const result = await axios(
            `http://127.0.0.1:5000/api/resources/products?url=${url}`,
        )
        addItem(result.data[0]);
    };

    let removeItem = (index) => {
        const newItems = [...items];
        newItems.splice(index, 1);
        setItems(newItems);
    };

    return (
        <div>
            <form className = {classes.formControl} onSubmit = {handleSubmit}>
                <TextField id = "outlined-basic" label = "Amazon Url" variant = "outlined" name='newItem' onChange = {e => setUrl(e.target.value)} value = {url} />
                <Button variant = "contained" color = "primary" type = "submit">
                    <AddIcon className = {classes.extendedIcon} />
                </Button>
            </form>


            <List className = {classes.root}>
                {items.map((item, index) => (
                    <React.Fragment key = {index}>
                        <AvatarListItem
                            itemDetails = {item}
                            key = {index}
                            index = {index}
                            removeItem = {removeItem}
                        />
                        <Divider variant = "middle" component = "li" />
                    </React.Fragment>
                ))}
            </List>
        </div >
    );
}

если вы намерены получать данные каждый раз, когда пользователь нажимает submit, основываясь на вашем useEffect, вы должны основывать свой useEffect не на search, а на самом items (например, когда пользователь отправляет, вы добавляете что-то к items)

ваш код должен выглядеть так

   useEffect(() => {
        const fetchData = async () => {
            const result = await axios(
                `http://127.0.0.1:5000/api/resources/products?url=${url}`,
            )
            setItemDetails(result.data[0]);
        }
        fetchData()
    }, [items])

Другие вопросы по теме