[英]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.