繁体   English   中英

API 没有调用第一次渲染,只有在我手动重新渲染 React 应用程序之后

[英]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>
        )
      }
    }

我试过的:

  • POST 请求的 url 是正确的,因为它将在其第二次呈现中成功呈现。 我已将其移至 a.env 变量,因为端点是敏感的
  • 我试图使 GET 请求异步,但我不确定在 POST 请求成功之前是否正在发出 GET 请求。 在检查 .network 选项卡时,POST 请求似乎需要 956 毫秒才能成功。
  • 我不认为这是 CORS 的问题,因为我已将模式设置为 CORS 并且我还使用了 Edge 插件来禁用 CORS 我仍然遇到同样的问题
  • 我尝试使用一个名为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM