我正在尝试使用 React 的
react-select
自定义组件更新选择,由于获取数据时发生竞争条件,我无法为其填充所选值。我已经看过几个关于如何处理 useEffect
中的 fetch 调用以及如何处理它们的问题,但没有任何效果...不确定这是否与 fetch
API 中的竞争条件或承诺有关我处理不当。
AlergiaForm.component.tsx
import Select, { SingleValue} from "react-select";
import {useState, useEffect} from "react";
interface IOption {
value: string | null;
label: string;
icon?: string;
}
interface IProduct {
id: number,
title: string
}
const AlergiaForm = () => {
const[products, setProducts] = useState(Array<IProduct>);
const[product, setProduct] = useState<SingleValue<IOption> | null>(null);
const[isLoading, setLoading] = useState(false);
const[value, setValue] = useState<string | null | undefined>("");
//Mapper
const mapper = ():IOption[] => {
return products.map(item => {
return { value: item.id, label: item.title};
}) as unknown as IOption[];
}
useEffect(() => {
//Get product, like an edit
const getProduct = () => {
setLoading(true);
fetch('https://dummyjson.com/products/6')
.then(res => res.json())
.then((data) => {
//We get the products dropdown values and we are waiting for it... is not even async and I'm waiting on the promise I think?
getProducts();
setLoading(false);
//Logic to "set" the current value, but since it has a race condition, it's not picking it up
//Works when a hot module refresh happens in Vite because the context is updated already... but not on page "load" or react-router-dom navigation
const product = data as IProduct;
const {id} = {...product};
const selectedProduct = products.find(i => i.id === id) as IProduct;
const ioption = { value: selectedProduct?.id.toString(), label: selectedProduct?.title } as SingleValue<IOption>;
setProduct(ioption);
});
}
const getProducts = () => {
fetch('https://dummyjson.com/products')
.then(res => res.json())
.then((data) => {
const products = data.products as IProduct[];
setProducts(products);
});
}
getProduct();
}, []);
const handleDropDownChange = (selectedOption: SingleValue<IOption>):void => {
const { value } = {...selectedOption};
setValue(value);
}
return(
<>
<Select options={mapper()} value={isLoading ? null : product} onChange={handleDropDownChange} />
<p>Value selected: {product?.value ?? value}</p>
<p>Is Loading: {isLoading ? "Loading..." : "Done"}</p>
</>
)
}
export default AlergiaForm;
应用程序.tsx
import AlergiaForm from './AlergiaForm.component'
function App() {
return (
<main>
<AlergiaForm />
</main>
)
}
export default App;
具有相同代码的最小示例: 示例
您会看到检索产品时它不会更新所选值,这可能是因为尝试设置产品时未完成承诺,但不确定如何避免这种情况,即使等待实际响应以获得数据并正确设置值。
另一件事要提到的是,我正在使用
Vite
,每次重新加载保存文件上的页面时,都会选择该值,所以我知道代码正在工作,只是我猜问题是这里的竞争条件。
文章阅读:https://maxrozen.com/fetching-data-react-with-useeffect
https://overreacted.io/a-complete-guide-to-useeffect/
useEffect(() => {
getProducts();
}, []);
const getProducts = () => {
fetch('https://dummyjson.com/products')
.then(res => res.json())
.then((data) => {
const products = data.products as IProduct[];
setProducts(products);
getProduct(products)
});
}