在 api 调用期间无法更新状态以更改页面上的显示
Can't update state to change display on page during api call
我有一个名为 Dashboard
的页面,在此页面上有一个名为 Dropzone
的组件,用于将文件上传到该页面。
上传文件时,它会调用 onDrop()
回调,我 POST 将文件发送到 api,然后我尝试向 [=] 发送 GET 请求36=] 在 /api/machines/{hash}
。我想在此 GET 请求之前将我的 state.pcapAnalysing
变量设置为 TRUE
,并在它完成后将其设置为 FALSE
。这样做的想法是在仪表板页面上显示一条 'analysing' 消息,而 api 调用是 运行,这可能需要几秒钟才能到达 return。
由于状态未刷新,消息不会显示,因为状态从不更新以显示 state.pcapAnalysing
除了 false 之外的任何内容。有谁知道我怎样才能达到我想要的效果?本质上,我试图在 api 调用操作期间在 Dashboard
页面上显示一条消息,但它是由驻留在 Dropzone.js
中的组件触发的。谢谢。
Dashboard.js
...
export default function Dashboard() {
const [currentTime, setCurrentTime] = useState(0);
const [state, dispatch] = useContext(Context);
useEffect(() => {
fetch('/api/time').then(res => res.json()).then(data => {
setCurrentTime(data.time);
});
}, []);
return (
<PageBase navigation={navigation}>
<div className="flex place-content-center mt-10">
<div className="flex w-1/2 place-content-center">
{ !state.pcapUploaded ?
state.pcapAnalysing ?
<p>uploading</p> // Want to show this when state.pcapAnalysing is TRUE
:
<TwoCard numcols="2">
<div>
<h5 className="">Upload a PCAP file to analyse</h5>
<p>Accepted file types: .pcap, .pcapng, .tcpdump</p>
</div>
<div className="mt-5 lg:ml-2 lg:mt-0 md:mt-0">
<MyDropzone/>
</div>
</TwoCard>
:
<TwoCard numcols="3">
<div className='col-span-1'>
<img src={require("../Assets/pcap.png")}/>
</div>
<div className='col-span-2'>
<h5 className="">Selected File:</h5>
<p className="break-all">{state.pcapFileName}</p>
<p className="break-all">{state.pcapHash}</p>
<button type="button" onClick={clearPcap}>
Change
</button>
</div>
</TwoCard>
}
</div>
</div>
<div>
{ state.pcapUploaded ? <TileGrid tiles={tiles}/> : null }
</div>
</PageBase>
);
}
Dropzone.js
import { useCallback, useEffect, useContext } from 'react';
import { useDropzone } from 'react-dropzone';
import { Context } from '../Helpers/Provider';
export default function MyDropzone() {
const [state, dispatch] = useContext(Context);
const onDrop = useCallback(acceptedFiles => {
const formData = new FormData();
formData.append('file', acceptedFiles[0]);
fetch('/api/upload',
{
method: 'POST',
body: formData,
}
)
.then(res => res.json())
.then(result => {
console.log('Success: ', result);
console.log("dispatching...");
dispatch({
type: 'HASH',
payload: result['hash'],
});
dispatch({
type: 'ANALYSING', // Want to use this to set state.pcapAnalysing to TRUE
});
console.log("before: " + state.pcapAnalysing);
if (state.machineIPs == null) {
console.log("Machines: ", state.pcapHash);
fetch(`/api/machines/${result['hash']}`) // This request may take a few seconds
.then(res => res.json())
.then(data => {
console.log(data);
dispatch({
type: 'MACHINES',
payload: result,
});
});
};
dispatch({
type: 'ANALYSING', // Want to use this to set state.pcapAnalysing to false after request completes
});
console.log("after: " + state.pcapAnalysing);
})
}, [state.pcapHash])
const {getRootProps, getInputProps, isDragActive} = useDropzone({
onDrop,
maxFiles: 1,
accept: '.pcap, .pcapng, .tcpdump'
})
return (
<div {...getRootProps()} className="..<shortened>..">
Upload PCAP
<input {...getInputProps()} />
{
isDragActive ?
<p>Drop the file here ...</p> :
<p className="ml-2 mr-2">Drag 'n' drop a file here, or click to select file</p>
}
</div>
)
}
看起来您应该在 /api/machines
调用的 then
关闭 内设置最终状态 。不是之后。
所以整个调用应该是这样的:
fetch('/api/upload',
{
method: 'POST',
body: formData,
}
)
.then(res => res.json())
.then(result => {
console.log('Success: ', result);
console.log("dispatching...");
dispatch({
type: 'HASH',
payload: result['hash'],
});
dispatch({
type: 'ANALYSING', // Want to use this to set state.pcapAnalysing to TRUE
});
console.log("before: " + state.pcapAnalysing);
if (state.machineIPs == null) {
console.log("Machines: ", state.pcapHash);
fetch(`/api/machines/${result['hash']}`) // This request may take a few seconds
.then(res => res.json())
.then(data => {
console.log(data);
dispatch({
type: 'ANALYSING', // Want to use this to set state.pcapAnalysing to false after request completes
});
dispatch({
type: 'MACHINES',
payload: result,
});
});
};
})
}, [state.pcapHash])
注意我完全删除了那行
console.log("after: " + state.pcapAnalysing);
因为即使我在 then
关闭时移动它,状态也不会更新,因为组件 re-render 还没有发生。
我有一个名为 Dashboard
的页面,在此页面上有一个名为 Dropzone
的组件,用于将文件上传到该页面。
上传文件时,它会调用 onDrop()
回调,我 POST 将文件发送到 api,然后我尝试向 [=] 发送 GET 请求36=] 在 /api/machines/{hash}
。我想在此 GET 请求之前将我的 state.pcapAnalysing
变量设置为 TRUE
,并在它完成后将其设置为 FALSE
。这样做的想法是在仪表板页面上显示一条 'analysing' 消息,而 api 调用是 运行,这可能需要几秒钟才能到达 return。
由于状态未刷新,消息不会显示,因为状态从不更新以显示 state.pcapAnalysing
除了 false 之外的任何内容。有谁知道我怎样才能达到我想要的效果?本质上,我试图在 api 调用操作期间在 Dashboard
页面上显示一条消息,但它是由驻留在 Dropzone.js
中的组件触发的。谢谢。
Dashboard.js
...
export default function Dashboard() {
const [currentTime, setCurrentTime] = useState(0);
const [state, dispatch] = useContext(Context);
useEffect(() => {
fetch('/api/time').then(res => res.json()).then(data => {
setCurrentTime(data.time);
});
}, []);
return (
<PageBase navigation={navigation}>
<div className="flex place-content-center mt-10">
<div className="flex w-1/2 place-content-center">
{ !state.pcapUploaded ?
state.pcapAnalysing ?
<p>uploading</p> // Want to show this when state.pcapAnalysing is TRUE
:
<TwoCard numcols="2">
<div>
<h5 className="">Upload a PCAP file to analyse</h5>
<p>Accepted file types: .pcap, .pcapng, .tcpdump</p>
</div>
<div className="mt-5 lg:ml-2 lg:mt-0 md:mt-0">
<MyDropzone/>
</div>
</TwoCard>
:
<TwoCard numcols="3">
<div className='col-span-1'>
<img src={require("../Assets/pcap.png")}/>
</div>
<div className='col-span-2'>
<h5 className="">Selected File:</h5>
<p className="break-all">{state.pcapFileName}</p>
<p className="break-all">{state.pcapHash}</p>
<button type="button" onClick={clearPcap}>
Change
</button>
</div>
</TwoCard>
}
</div>
</div>
<div>
{ state.pcapUploaded ? <TileGrid tiles={tiles}/> : null }
</div>
</PageBase>
);
}
Dropzone.js
import { useCallback, useEffect, useContext } from 'react';
import { useDropzone } from 'react-dropzone';
import { Context } from '../Helpers/Provider';
export default function MyDropzone() {
const [state, dispatch] = useContext(Context);
const onDrop = useCallback(acceptedFiles => {
const formData = new FormData();
formData.append('file', acceptedFiles[0]);
fetch('/api/upload',
{
method: 'POST',
body: formData,
}
)
.then(res => res.json())
.then(result => {
console.log('Success: ', result);
console.log("dispatching...");
dispatch({
type: 'HASH',
payload: result['hash'],
});
dispatch({
type: 'ANALYSING', // Want to use this to set state.pcapAnalysing to TRUE
});
console.log("before: " + state.pcapAnalysing);
if (state.machineIPs == null) {
console.log("Machines: ", state.pcapHash);
fetch(`/api/machines/${result['hash']}`) // This request may take a few seconds
.then(res => res.json())
.then(data => {
console.log(data);
dispatch({
type: 'MACHINES',
payload: result,
});
});
};
dispatch({
type: 'ANALYSING', // Want to use this to set state.pcapAnalysing to false after request completes
});
console.log("after: " + state.pcapAnalysing);
})
}, [state.pcapHash])
const {getRootProps, getInputProps, isDragActive} = useDropzone({
onDrop,
maxFiles: 1,
accept: '.pcap, .pcapng, .tcpdump'
})
return (
<div {...getRootProps()} className="..<shortened>..">
Upload PCAP
<input {...getInputProps()} />
{
isDragActive ?
<p>Drop the file here ...</p> :
<p className="ml-2 mr-2">Drag 'n' drop a file here, or click to select file</p>
}
</div>
)
}
看起来您应该在 /api/machines
调用的 then
关闭 内设置最终状态 。不是之后。
所以整个调用应该是这样的:
fetch('/api/upload',
{
method: 'POST',
body: formData,
}
)
.then(res => res.json())
.then(result => {
console.log('Success: ', result);
console.log("dispatching...");
dispatch({
type: 'HASH',
payload: result['hash'],
});
dispatch({
type: 'ANALYSING', // Want to use this to set state.pcapAnalysing to TRUE
});
console.log("before: " + state.pcapAnalysing);
if (state.machineIPs == null) {
console.log("Machines: ", state.pcapHash);
fetch(`/api/machines/${result['hash']}`) // This request may take a few seconds
.then(res => res.json())
.then(data => {
console.log(data);
dispatch({
type: 'ANALYSING', // Want to use this to set state.pcapAnalysing to false after request completes
});
dispatch({
type: 'MACHINES',
payload: result,
});
});
};
})
}, [state.pcapHash])
注意我完全删除了那行
console.log("after: " + state.pcapAnalysing);
因为即使我在 then
关闭时移动它,状态也不会更新,因为组件 re-render 还没有发生。