簡體   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