ReactJS-axios.post的同步问题



我在reactjs中的axios.post调用出现同步问题。我有一个输入区域,用户可以选择一个本地文件提交到axios。post,该文件被翻译成arraybuffer,然后通过axios调用发送到microsoft faces api。如果我选择了一个图像,然后按下分析按钮,同步就会关闭,它会尝试在没有数组缓冲区的情况下发出post请求。如果我第二次点击它,它会使帖子正确。

我对等待和异步还相当陌生,对我的问题的任何输入都将是一个巨大的帮助。我想过使用布尔标志,但想学习如何通过正确的设计来改进这个函数。

import React, { useState } from "react";
import axios from "axios";
import { Button, Container, Row, Col } from "react-bootstrap";
import "../../styling/FacialRecognition.css";
import defaultImage from "../../assets/images/defaultImage.png";
function FacialRecognition() {
const [image, setImage] = useState("");
const [imageData, setImageData] = useState([]);
const [responseData, setResponseData] = useState([]);
const [dataLoad, setDataLoad] = useState(false);

//translates the local file to the array buffer, and sets the imageData.
function TranslateImageToArrayBuffer(imageToTranslate) {
let reader = new FileReader();
reader.readAsArrayBuffer(imageToTranslate);
reader.onloadend = () => {
setImageData(reader.result);
};
}

//Makes the call with the url,options, and the arraybuffer.
function ProcessImage(localImage) {
TranslateImageArrayBuffer(localImage);
console.log("ImageData: " + imageData);

var subscriptionKey = "<subscriptionkey>";
var uriBase =
"https://(urlgoeshere).cognitiveservices.azure.com/face/v1.0/detect";
const options = [
"returnFaceId=true",
"returnFaceLandmarks=true",
"returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,accessories",
];
uriBase = uriBase.concat("?", options.join("&"));
// Perform the REST API call.
axios
.post(uriBase, imageData, {
headers: {
"Content-Type": "application/octet-stream",
"Ocp-Apim-Subscription-Key": subscriptionKey,
},
})
.then(function (response) {
// Display the image.
var blob = new Blob([imageData]);
var url = URL.createObjectURL(blob);
setDataLoad(true);
document.querySelector("#sourceImage").src = url;
console.log("Status text: " + response.status);
console.log("Status text: " + response.statusText);
console.log(response.data);
setResponseData(response.data);
})
.catch(function (error) {
console.log(error);
});
}
let value = responseData.map((e) => JSON.stringify(e, null, 2));
return (
<div>
<Container fluid="xl">
<Row>
<Col xs="auto">
<p>
Select a local image, and then click the <b>Analyze face button.</b>
</p>
</Col>
</Row>
<Row>
<Col x="auto">
<label>Image to analyze: </label>
<input
type="file"
name="inputImage"
id="inputImage"
autoComplete="off"
accept="image/png, image/jpeg"
onChange={(e) => setImage(e.target.files[0])}
style={{ width: "60%", marginLeft: "1vw" }}
/>
<Button
variant="info"
onClick={() => ProcessImage(image)}>
Analyze face
</Button>
</Col>
</Row>
<Row style={{ marginTop: "2vw" }}>
<Col xs="6">
<label>
<strong>Response</strong>
</label>
</Col>
<Col xs="auto">
<label>
<strong>Source Image</strong>
</label>
</Col>
</Row>
<Row>
<Col>
{dataLoad ? (
<textarea
id="responseTextArea"
className="UIInput"
style={{ width: "100%", height: "429px" }}
value={value}
readOnly={true}
disabled="disabled"></textarea>
) : (
<textarea
id="responseTextArea"
className="UIInput"
style={
dataLoad
? { display: "none" }
: { width: "100%", height: "auto" }
}
defaultValue="This field will display analyzed data on the image"
readOnly={true}
disabled="disabled"></textarea>
)}
</Col>
<Col xs="6">
{dataLoad ? (
<img
id="sourceImage"
alt=""
style={
dataLoad
? { width: "80%" }
: { display: "none" }
}
/>
) : (
<img
id="defaultImage"
src={defaultImage}
alt=""
style={
dataLoad
? { display: "none" }
: { width: "80%" }
}
/>
)}
</Col>
</Row>
</Container>
</div>
);
}
export default FacialRecognition;

我还尝试将TranslateImageToArrayBuffer设置为异步函数,并将axios调用放入.then(response => {axios.post...})中,但没有成功。

编辑:我还尝试过将翻译函数的内容包装在promise中。

async function TranslateImageToArrayBuffer(imageToTranslate) {
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.onload = () => {
setImageData(reader.result);
resolve(imageData);
};
reader.onerror = () => {
reject(reader.result);
};
reader.readAsArrayBuffer(imageToTranslate);
});
}

并使用我的ProcessImage函数中的CCD_ 3行来等待该值。仍然存在同步问题。

我无法让它与异步一起工作,所以我移动了onChange函数来输入一个文件,将图像转换为数组缓冲区,而不是在ProcessImage()中进行调用。

<input
type="file"
name="inputImage"
id="inputImage"
autoComplete="off"
accept="image/png, image/jpeg"
onChange={(e) =>{ TranslateImageToArrayBuffer(e.target.files[0]);setImage(e.target.files[0]) }}
style={{ width: "60%", marginLeft: "1vw" }}
/>
<Button
variant="info"
onClick={() => ProcessImage()}>
Analyze face
</Button>

这样就不需要进行异步设置。

最新更新