Tengo un componente de reacción simple. El componente tiene un controlador que se ejecuta cuando se hace clic en el botón. Hay algún código de bloqueo en el controlador. Mi tarea es: cuando hago clic en el botón, aparece el cargador. Después de eso, el código de bloqueo realiza algunas operaciones pesadas y luego el cargador desaparece:
import { useState } from "react"; import "./styles.css"; export default function App() { const [wait, setWait] = useState(true); const onClickHandler = () => { setWait(true); // Blocking code setWait(false); }; return ( <div className="App"> <button onClick={onClickHandler}>Click</button> {wait && <div>Loading...</div>} </div> ); }Este código es artificial y sé que es mejor no hacer esto: bloquear el hilo. Sé que el procesamiento por lotes funciona aquí. Pero aún así, me gustaría saber cómo puedo mostrar el cargador en esta situación. Y en general, ¿es posible tal situación en la producción, o es una mala práctica?
Bloquear el código significa que cualquier otra operación en tu página tendrá que esperar hasta que finalice la primera. Si no le importa que esto suceda (tal vez este cargador cubre toda la pantalla o no desea que el usuario haga nada más hasta que finalice la operación), entonces está bien.
Ahora, tal vez quieras realizar esta operación mientras el usuario interactúa con la página, en ese caso deberías hacer uso del comportamiento asíncrono de Promise , usando la sintaxis then / catch / finally . También necesitará useRef para poder tener acceso al estado actual del componente en las devoluciones de llamada.
import { useState, useRef } from "react"; import "./styles.css"; export default function App() { // your big operation should return a Promise const bigOperation = () => { return new Promise((resolve, reject) => { resolve("Heeeey"); }) } // added "_" to the set function so it won't be confused // with our function to update the reference const [wait, _setWait] = useState(true); // create reference for the wait state const waitRef = useRef(wait); // function to update reference and state (mimics real one _setWait) const setWait = (newValue) => { waitRef.current = newValue; _setWait(newValue); } const onClickHandler = () => { setWait(true); // this executes asyncronously bigOperation().then(() => { setWait(false); }); }; return ( <div className="App"> <button onClick={onClickHandler}>Click</button> {wait && <div>Loading...</div>} </div> ); }Hay dos maneras de hacer esto
new Promise o setTimeout servirán.
export default function App() { const [wait, setWait] = useState(true); const onClickHandler = () => { setWait(true); new Promise((resolve) => { // Blocking code setWait(false); resolve() }); }; return ( <div className="App"> <button onClick={onClickHandler}>Click</button> {wait && <div>Loading...</div>} </div> ); } Puede usar ganchos personalizados como useWorker para lograr esto convenientemente
useWorker : https://github.com/alewin/useWorker
Movería la condición fuera de la declaración de devolución principal.
if (wait) return <div>Loading...</div>; return ( <div className="App"> <button onClick={onClickHandler}>Click</button> </div> );