Axios + React (Next.js), почтовый запрос теряет контекст/состояние

Я ломал голову часами, эта ошибка не имеет для меня никакого смысла.

Подобно этой решенной проблеме, контекст и состояние реакции теряются после завершения запроса. Единственная проблема в том, что все мои функции уже привязаны.

Приведенный ниже код должен возвращать URL-адрес изображения и добавлять его в состояние массива «изображение» каждый раз при нажатии кнопки. Что не работает, так это то, что содержимое состояния массива «image» волшебным образом забывается внутри обещания axios, а это означает, что все предыдущие изображения теряются, и только изображение, возвращенное запросом, окажется в состоянии.

Со мной никогда раньше не случалось ничего подобного, я чувствую, что должен упустить какую-то невероятно глупую ошибку, которую совершил. У кого-нибудь есть идеи, что здесь может происходить?

Спасибо,

// Added
const RANDOM_PROMPTS = [
    'a whale flying in the sky',
    'a skeleton dancing',
    'a sunflower growing in a field'
]

export default function Home() {

    const [prompt, setPrompt] = useState('')
    const [images, setImages] = useState([])

    // Added
    useEffect(() => {
        randomPrompt()
    }, []) 

    const handleSubmit = event => {
        event.preventDefault()
        event.stopPropagation()

        axios.post('http://localhost:3000/v1/generate', {prompt})
        .then(res => {
            res.data && add(res.data.url)
        })
    }

    const add = (url) => {
        // images state is always [] here
        console.info(images)
        setImages([...images, url])
    }
    
    // Added
    const randomPrompt = () => {
        const prompt = RANDOM_PROMPTS.shift()
        
        setPrompt(`a painting of ${prompt}, by Paul Delvaux`)
    }

    return (
        <div>
            <form onSubmit = {handleSubmit}>
                <input type = "text" value = {prompt} onChange = {event => setPrompt(event.target.value)}/>
                <button type = "submit">Draw</button>
            </form>
        </div>
    )
}

Вы пытались инициировать запрос Axios в другой функции, которая выполняется с использованием хука useEffect()? (Я имею в виду, что handleSubmit может изменить переменную, которая будет зависимостью для useEffect)

Ozgur Sar 14.09.2022 12:01

У меня был хук useEffect, но, насколько я понимаю, он не был связан или каким-либо образом инициировал запрос axios. Тем не менее, когда я удалил его, он начал работать, как и ожидалось. UseEffect использовался для рандомизации подсказки при монтировании, я отредактировал вопрос и добавил его в код. Если вы понимаете, как это может нарушить запрос axios, я хотел бы услышать, что вы думаете.

August Bjornberg 14.09.2022 13:15

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

August Bjornberg 14.09.2022 13:23

Я думаю, KALrious указал на хороший момент. Я отредактировал свой ответ, включив в него useEffect с асинхронным вызовом функции. Его ответ также должен решить проблему.

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

Ответы 2

Случайные подсказки не должны влиять на запрос Axios, который вы делаете для другой зависимости useEffect(). Пожалуйста, попробуйте мой код ниже, в котором я пытался сделать то, что предложил в своем комментарии.

const RANDOM_PROMPTS = [
    'a whale flying in the sky',
    'a skeleton dancing',
    'a sunflower growing in a field'
]

export default function Home() {

    const [prompt, setPrompt] = useState('')
    const [images, setImages] = useState([])
    const [initiateRequest, setInitiateRequest] = useState(false)

    // Added
    useEffect(() => {
        randomPrompt()
    }, []) 

async function fetchData() {
    let response = axios.post('http://localhost:3000/v1/generate', {prompt})
        .then(res => {
            res.data && add(res.data.url)
        })
  }
    useEffect(() => {
        fetchData()
    }, [initiateRequest]) 

    const handleSubmit = event => {
        event.preventDefault()
        event.stopPropagation()
        setInitiateRequest(true)
    }

    const add = (url) => {
        // images state is always [] here
        console.info(images)
        setImages([...images, url])
    }
    
    // Added
    const randomPrompt = () => {
        const prompt = RANDOM_PROMPTS.shift()
        
        setPrompt(`a painting of ${prompt}, by Paul Delvaux`)
    }

    return (
        <div>
            <form onSubmit = {handleSubmit}>
                <input type = "text" value = {prompt} onChange = {event => setPrompt(event.target.value)}/>
                <button type = "submit">Draw</button>
            </form>
        </div>
    )
}

Это так странно, асинхронность не имеет никакого значения. Это должно было быть первым, что я попробовал, хотя я почти никогда не использую .then(). KALrious answer научил меня, что я могу использовать prevState в преобразователе при настройке состояния, я понятия не имел, что это возможно. Это кажется самым чистым решением. Хотя я все еще несколько сбит с толку тем, что контекст просто теряется, но рад, что есть изящное решение. Спасибо за помощь, Озгур Сар

August Bjornberg 14.09.2022 14:05
Ответ принят как подходящий

Вы пытались заставить свою функцию обрабатывать асинхронную функцию Submit?

 const handleSubmit = async (event) => {
        event.preventDefault()
        event.stopPropagation()

        const {data} = await axios.post('http://localhost:3000/v1/generate', 
        {prompt},{
         validateStatus: (status) => status === 201,
        })
        if (!!data && !!data.url) {
          add(data.url)
        }
    }

Je rajouterais que tu peux modifier ta fonction add comme suit:

const add = (url) => {
        console.info(images)
        setImages((prevState) => [...prevState, url])
    }

Я считаю, что во время .then вы можете потерять контекст своего состояния реакции.

Async + await handleSumbit не имеет значения, но "setImages((prevState) => [...prevState, url])" работает! Вау, я понятия не имел, что могу использовать prevState таким образом в хуке setState, и я реагировал годами, лол. Чем больше ты знаешь. Спасибо KALrious. Меня все еще довольно сбивает с толку то, что контекст просто потерян, но я рад, что вы нашли решение.

August Bjornberg 14.09.2022 13:58

Пожалуйста, чтобы помочь вам немного ;)

KALrious 14.09.2022 17:22

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

Похожие вопросы

TS7053: Элемент неявно имеет тип «любой», поскольку выражение типа «строка» не может использоваться для индексации типа «{имя пользователя: строка; электронная почта: строка;
Как использовать useEffect Hook для выполнения операции только один раз?
Получите один запрос данных с идентификатором или слагом на Inertiajs и реагируйте на код
Как проверить, какой функциональный компонент React был просмотрен в окне просмотра последним?
Функциональный компонент не обновляет DOM при обновлении состояния с помощью useState
Доступ к отправке инструментария redux в пользовательском хуке с помощью приложения nextjs
Как загрузить записанное аудио (Blob) на сервер? - РеактJS
Невозможно назначить свойство "url" объекта "#<Object>" только для чтения
Тег списка данных не прослушивает ни одно событие, реагирующее на js
Antd ImgCrop, когда minZoom ниже 1, всегда обрезается, как масштаб 1