我是 React 的新手,我想實作一個表單,其中給用戶 N 個輸入并被要求在其中復制/粘貼一些內容(他也可以單擊 或 - 按鈕來添加或洗掉一些輸入,但讓我們現在保持簡單)。
這個想法是,對于每個輸入,用戶將復制/粘貼一些資料,并且在每個輸入onChange上附加一個偵聽器,以便每次更改輸入時,它都會觸發對 API 或后端服務的呼叫以驗證資料. 驗證資料后,它將回傳用戶是否正確(例如通過更改輸入的背景顏色)。這是一張圖片:

問題是,假設用戶在第一個輸入中復制/粘貼大猩猩并且異步呼叫需要10s,但是在第一個輸入中復制/粘貼大猩猩后2s后,他在第二個輸入中復制/粘貼宇宙飛船(這異步呼叫需要 4 秒才能回傳,比如說)。我當前版本的情況是,由于第二個呼叫在第一個呼叫之前完成,isValid因此會針對第二個輸入進行更新,而不是針對第一個輸入進行更新。
這是由于我正在使用useEffect和clean功能。我也嘗試過使用useState,但每次遇到競爭情況時......
備注:
- 如果用戶在第一次輸入時輸入了 gorilla,在他修改相同的輸入后 1s 輸入了 giraffe。如果第一個異步呼叫還沒有完成,我寧愿殺死它,只檢索對同一輸入進行的最新呼叫的驗證(這就是為什么我在我的
useEffect. - 即使解決了停止驗證其他輸入的問題,我認為總會存在競爭條件,因為
useEffect我正在修改與我的每個輸入相關聯的 useState,所以我不確定如何去做。
這是復制我當前行為的小樣本:
import React, { useEffect, useState } from "react";
export default function MyComponent(props) {
let delay = 10000; // ms
const [data, setData] = useState(
Array(5).fill({
isValid: 0,
url: null
})
);
const [inputIdx, setInputIdx] = useState(-1);
const updateData = (index, datum) => {
const updatedData = data;
updatedData[index] = datum;
setData([...updatedData]);
setInputIdx(index);
delay /= 2;
};
useEffect(() => {
let canceled = true;
new Promise((resolve) => {
setTimeout(() => resolve("done"), delay);
}).then((e) => {
if (canceled) {
const updatedData = data;
updatedData[inputIdx].isValid = true ^ updatedData[inputIdx].isValid;
setData([...updatedData]);
}
});
return () => {
canceled = false;
};
}, [inputIdx]);
const processData = data.map((datum, index) => {
return (
<input
type="text"
onChange={e =>
updateData(index, {
url: e.target.value === "" ? null : e.target.value,
isValid: data[index].isValid,
})
}
style={{display:"block"}}
/>
);
});
return (
<div>
<div>{processData}</div>
<div>{JSON.stringify({data})}</div>
</div>
);
}
這是一個
uj5u.com熱心網友回復:
我認為你不需要useEffect這個。您可以只收聽輸入中的粘貼事件,運行 API 呼叫并做出相應的回應。我包括了一個最小的可驗證示例。這是一個概念證明,但您可以更改實際應用程式中組件的邊界和職責。 Run代碼并將每個單詞粘貼到輸入中,以查看輸出中反映的狀態變化。
function App() {
const [state, setState] = React.useState({
"gorilla": "pending",
"broccoli": "pending",
"cage": "pending",
"motorcycle": "pending"
})
const expect = expected => actual =>
setState(s => ({...s, [expected]: expected == actual }))
return <div>
<p>gorilla spaceship cage bike</p>
<ValidateInput valid={state.gorilla} validate={expect("gorilla")} />
<ValidateInput valid={state.broccoli} validate={expect("broccoli")} />
<ValidateInput valid={state.cage} validate={expect("cage")} />
<ValidateInput valid={state.motorcycle} validate={expect("motorcycle")} />
<pre>{JSON.stringify(state)}</pre>
</div>
}
function ValidateInput({ valid, validate }) {
function onPaste(event) {
const pasted = event.clipboardData.getData("text/plain")
someApiCall(pasted).then(validate).catch(console.error)
}
return <input className={String(valid)} onPaste={onPaste} />
}
function someApiCall(v) {
return new Promise(r => setTimeout(r, Math.random() * 6000, v))
}
ReactDOM.render(<App/>, document.querySelector("#app"))
input { display: block; outline: 0; }
input.true { border-color: green; }
input.false { border-color: red; }
pre { padding: 0.5rem; background-color: #ffc; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/437401.html
標籤:reactjs asynchronous react-hooks use-effect race-condition
