Я ломал голову часами, эта ошибка не имеет для меня никакого смысла.
Подобно этой решенной проблеме, контекст и состояние реакции теряются после завершения запроса. Единственная проблема в том, что все мои функции уже привязаны.
Приведенный ниже код должен возвращать 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>
)
}
У меня был хук useEffect, но, насколько я понимаю, он не был связан или каким-либо образом инициировал запрос axios. Тем не менее, когда я удалил его, он начал работать, как и ожидалось. UseEffect использовался для рандомизации подсказки при монтировании, я отредактировал вопрос и добавил его в код. Если вы понимаете, как это может нарушить запрос axios, я хотел бы услышать, что вы думаете.
И большое спасибо за помощь в исправлении. Кроме того, должен ли я теперь беспокоиться о том, что хуки useEffect нарушают аксиомы из совершенно другой части приложения?
Я думаю, KALrious указал на хороший момент. Я отредактировал свой ответ, включив в него useEffect с асинхронным вызовом функции. Его ответ также должен решить проблему.
Случайные подсказки не должны влиять на запрос 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 в преобразователе при настройке состояния, я понятия не имел, что это возможно. Это кажется самым чистым решением. Хотя я все еще несколько сбит с толку тем, что контекст просто теряется, но рад, что есть изящное решение. Спасибо за помощь, Озгур Сар
Вы пытались заставить свою функцию обрабатывать асинхронную функцию 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. Меня все еще довольно сбивает с толку то, что контекст просто потерян, но я рад, что вы нашли решение.
Пожалуйста, чтобы помочь вам немного ;)
Вы пытались инициировать запрос Axios в другой функции, которая выполняется с использованием хука useEffect()? (Я имею в виду, что handleSubmit может изменить переменную, которая будет зависимостью для useEffect)