[英]API is not calling on first render, only after I manually re-render React app
I am calling the Azure Optical Character Recognition API in my React app that requires an initial POST request to get an 'operation-location' value from the response header. The 'operation-location' value is then used to make a GET request.我在我的 React 应用程序中调用 Azure 光学字符识别 API,它需要初始 POST 请求以从响应 header 中获取“操作位置”值。然后使用“操作位置”值发出 GET 请求。
The API takes an url to an image with text and returns the plain text from the image. API 将 url 用于带文本的图像,并返回图像中的纯文本。
The issue I am facing is that the POST request is only successful when I manually re-render the React app .我面临的问题是POST 请求只有在我手动重新渲染 React 应用程序时才会成功。 I submit this url https://i.stack.imgur.com/i1Abv.png via the UI I have created, both POST and GET requests fail but they will only be successful when I hit ctrl + S on the development environment.我通过我创建的 UI 提交了这个 url https://i.stack.imgur.com/i1Abv.png,POST和 GET 请求都失败了,但只有当我在开发环境中按 ctrl + S 时它们才会成功。
When I log the 'operation-location' value on the first render, it returns null so the GET request is made to http://localhost:5173/null and so it fails.当我在第一次呈现时记录“操作位置”值时,它返回 null,因此向 http://localhost:5173/null 发出 GET 请求,因此失败。 But, when I manually re-render the app by hitting save, both API calls are successful and the getText
variable is rendered.但是,当我通过点击保存手动重新呈现应用程序时,两个 API 调用都成功并且呈现了getText
变量。
getText
is a stateful variable that I am updating with the text from the image getText
是一个有状态变量,我正在用图像中的文本更新它
I am trying to make it so it is successful on the first load.我正在努力让它在第一次加载时成功。
On the first render, I get an error TypeError: Cannot read properties of undefined (reading 'analyzeResult') when trying to resolve .then((json)=> {
within the getData
function在第一次渲染时,我收到错误 TypeError: Cannot read properties of undefined (reading 'analyzeResult') when trying to resolve .then((json)=> {
within the getData
function
The POST request takes a user input in the body of the request from props.UserUrl which comes from the file Homepage.jsx: 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>
)
}
}
} }
The API is called in Api.jsx: 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>
)
}
}
What I have tried:我试过的:
loading
to re-render React on API call but still facing same issue of it only working on a manual re-render我尝试使用一个名为loading
的有状态变量在 API 调用上重新渲染 React,但仍然面临同样的问题,它只能在手动重新渲染时工作data
to re-render React on API call but still facing same issue of it only working on a manual re-render我尝试使用一个名为data
的有状态变量在 API 调用上重新渲染 React,但仍然面临同样的问题,它只适用于手动重新渲染props.UserUrl
as a stateful variable but was running into an endless loop我尝试使用props.UserUrl
作为有状态变量,但遇到了无限循环responseHeaders
to force the API to re-render but I was still facing the same issues我尝试使用有状态变量来捕获responseHeaders
以强制 API 重新呈现,但我仍然面临同样的问题operationLocation
value to the useEffect array but it created an endless loop我将operationLocation
值添加到 useEffect 数组,但它创建了一个无限循环location.reload()
to re-render React but it just reloaded back to the initial UI and lost the data我尝试使用location.reload()
重新渲染 React,但它只是重新加载回初始 UI 并丢失了数据I think I need to force React to re-render someway but I don't know how.我想我需要强制 React 以某种方式重新渲染,但我不知道该怎么做。
add the POST request in another useEffect with no dependency so the useEffect will run only once when the app load first time在另一个没有依赖关系的 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.