[英]API is not calling on first render, only after I manually re-render React app
我在我的 React 應用程序中調用 Azure 光學字符識別 API,它需要初始 POST 請求以從響應 header 中獲取“操作位置”值。然后使用“操作位置”值發出 GET 請求。
API 將 url 用於帶文本的圖像,並返回圖像中的純文本。
我面臨的問題是POST 請求只有在我手動重新渲染 React 應用程序時才會成功。 我通過我創建的 UI 提交了這個 url https://i.stack.imgur.com/i1Abv.png,POST和 GET 請求都失敗了,但只有當我在開發環境中按 ctrl + S 時它們才會成功。
當我在第一次呈現時記錄“操作位置”值時,它返回 null,因此向 http://localhost:5173/null 發出 GET 請求,因此失敗。 但是,當我通過點擊保存手動重新呈現應用程序時,兩個 API 調用都成功並且呈現了getText
變量。
getText
是一個有狀態變量,我正在用圖像中的文本更新它
我正在努力讓它在第一次加載時成功。
在第一次渲染時,我收到錯誤 TypeError: Cannot read properties of undefined (reading 'analyzeResult') when trying to resolve .then((json)=> {
within the getData
function
POST 請求在來自文件 Homepage.jsx 的 props.UserUrl 的請求正文中獲取用戶輸入:
import {React, useState} from 'react'
import Api from './Api';
export default function Homepage(props){
const [isClicked, setIsClicked] = useState(false)
const [input, setInput] = useState('');
const [text, setText] = useState('')
function handleChange (e) {
setInput(e.target.value)
}
function handleClick(){
setText(input)
setIsClicked(true);
}
{if (isClicked == true){
return (
<div>
<Api UserUrl={text}/>
</div>
)
} else {
return (
<div className="image-input">
<input type="text" placeholder='enter url you want to convert' onChange={handleChange}/>
<button onClick={handleClick}>Submit</button>
</div>
)
}
}
}
API在Api.jsx中調用:
import { React, useState, useEffect } from 'react';
export default function Api(props) {
// Need this unique value to send the GET request. We receive it from the POST request
const [operationLocation, setOperationLocation] = useState(null);
// We will add the text from the image to this variable
const [getText, setGetText] = useState(null);
const [userUrl, setUserUrl] = useState('');
const [loading, setLoading] = useState(false);
const [responseHeaders, setResponseHeaders] =useState ({})
// We make a POST request to this URL
let url = `${import.meta.env.VITE_ENDPOINT}.cognitiveservices.azure.com/vision/v3.2/read/analyze`;
// Options for POST request
const options = {
// Change the image url to any you like that has text
body: (JSON.stringify({ "url": props.UserUrl })),
headers: {
// Need to set this parameter or else won't work due to CORS
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
// This is the value we need to get in the header request
"Access-Control-Expose-Headers": "operation-location",
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": import.meta.env.VITE_API_KEY
},
method: "POST",
mode: 'cors',
credentials: "same-origin"
};
// Options for Get request
const optionsGet = {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
'Accept': 'application/json',
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": import.meta.env.VITE_API_KEY
},
method: "GET",
mode: 'cors',
credentials: "same-origin"
};
useEffect(()=> {
// Post request
const fetchData = async () => {
setLoading(true)
fetch(url, options)
// Setting the operation location value from the header
.then((res) => {
return setOperationLocation(res.headers.get('operation-location'))
})
// On first render, operationLocation value is not being returned, returns null
.then(console.log(operationLocation))
}
// Get request
const getData = () => {
// Passing the operation location value from the POST request into our GET request
fetch(operationLocation, optionsGet)
.then((res) => {
if (res.ok) {
return res.json()
}
})
.then((json)=> {
// The response returns an array of text. The text gets broken up into multiple lines
const textArray = json.analyzeResult.readResults[0].lines;
// Map through the response to get each individual text
const textOutput = textArray.map(item => item.text) //returns an array
// Use the join method to get rid of the commas in the array so it returns a string
const textOutputString = textOutput.join(' ')
setGetText(textOutputString)
setLoading(false)
})
.catch(err => {
console.log(err)
})
}
// Asyncrhonously make the requests. We need to wait for response from the POST request before we execute the GET request
async function callApi () {
await fetchData ()
console.log('post request successful')
console.log(operationLocation)
await getData()
console.log('get request succesful')
setLoading(false)
}
callApi();
}, [props.UserUrl])
// We check to see if the request has populate state and then we render the response
if (loading) {
return (
<div>
Loading...
</div>
)} else {
return (
<div className="center">
<p>{getText}</p>
<p>{props.UserUrl}</p>
</div>
)
}
}
我試過的:
loading
的有狀態變量在 API 調用上重新渲染 React,但仍然面臨同樣的問題,它只能在手動重新渲染時工作data
的有狀態變量在 API 調用上重新渲染 React,但仍然面臨同樣的問題,它只適用於手動重新渲染props.UserUrl
作為有狀態變量,但遇到了無限循環responseHeaders
以強制 API 重新呈現,但我仍然面臨同樣的問題operationLocation
值添加到 useEffect 數組,但它創建了一個無限循環location.reload()
重新渲染 React,但它只是重新加載回初始 UI 並丟失了數據我想我需要強制 React 以某種方式重新渲染,但我不知道該怎么做。
在另一個沒有依賴關系的 useEffect 中添加 POST 請求,這樣 useEffect 只會在應用程序第一次加載時運行一次
useEffect(()=> {
// Post request
const fetchData = async () => {
setLoading(true)
fetch(url, options)
// Setting the operation location value from the header
.then((res) => {
return setOperationLocation(res.headers.get('operation-location'))
})
// On first render, operationLocation value is not being returned, returns null
.then(console.log(operationLocation))
}
}, [])
useEffect(()=> {
// Get request
const getData = () => {
// Passing the operation location value from the POST request into our GET request
fetch(operationLocation, optionsGet)
.then((res) => {
if (res.ok) {
return res.json()
}
})
.then((json)=> {
// The response returns an array of text. The text gets broken up into multiple lines
const textArray = json.analyzeResult.readResults[0].lines;
// Map through the response to get each individual text
const textOutput = textArray.map(item => item.text) //returns an array
// Use the join method to get rid of the commas in the array so it returns a string
const textOutputString = textOutput.join(' ')
setGetText(textOutputString)
setLoading(false)
})
.catch(err => {
console.log(err)
})
}
// Asyncrhonously make the requests. We need to wait for response from the POST request before we execute the GET request
async function callApi () {
await fetchData ()
console.log('post request successful')
console.log(operationLocation)
await getData()
console.log('get request succesful')
setLoading(false)
}
callApi();
}, [props.UserUrl])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.