¿Cómo se almacena correctamente el valor de una función de promesa sin demora?
Estoy intentando usar un gancho useEffect, pero aún así mi estado se retrasa.
Es problemático ya que si el usuario está validando su carrito, se puede aplicar un impuesto incorrecto.
useEffect(() => { SalesTax.getSalesTax(country, region).then((tax) => { setTax(tax.rate); }); }, [region]); <RegionDropdown country={country} className="capitalize input" value={region} onChange={(val) => { setRegion(val); }} required countryValueType="short" valueType="short" />Deberías hacer algo como esto:
const [loading, setLoading] = useState(false); useEffect(() => { setLoading(true); SalesTax.getSalesTax(country, region).then((tax) => { setTax(tax.rate); setLoading(false); }); }, [region]); if (loading) { return <p>Loading...<p/>; }Esta es una forma normal de manejar acciones asincrónicas en React.
Usará muchos valores asincrónicos, entonces, ¿qué le parece hacer un gancho como useAsync ?
function useAsync(f, [_0, _1, _2, _3, _4]) { const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [result, setResult] = useState(null) useEffect(_ => { setLoading(true) Promise.resolve(f(_0, _1, _2, _3, _4)) .then(setResult, setError) .finally(_ => setLoading(false)) }, [f, _0, _1, _2, _3, _4]) return {loading, error, result} }Ahora usa tu gancho en tu componente -
function MyComponent({country, region}) { const {loading, error, result} = useAsync(SalesTax.getSalesTax, [country, region]) if (loading) return <p>Loading...</p> else if (error) return <p>Error: {error.message}</p> else /* result is usable here */ return <RegionDropdown .../> } _0 , _1 , _2 , ... son necesarios para que ESLint pueda analizar estáticamente las dependencias. En una versión futura, quizás se pueda usar una matriz. Otra opción es deshabilitar ESLint para este enlace, pero tenga en cuenta que Dan Abramov de React lo desaconseja :
function useAsync(f, args) { const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [result, setResult] = useState(null) useEffect(_ => { setLoading(true) Promise.resolve(f(...args)) .then(setResult, setError) .finally(_ => setLoading(false)) }, // eslint-disable-next-line react-hooks/exhaustive-deps [f, ...args]) return {loading, error, result} }