Tengo una matriz de objetos y cada objeto tiene un valor de propiedad falso de forma predeterminada:
const [items, setItems] = useState([ { key: 1, has_x: false }, { key: 2, has_x: false }, { key: 3, has_x: false } ]);Que se transmite a los componentes secundarios:
<Item key={item.key} hasX={item.has_x} />En el componente principal, tengo un botón "Marcar todo":
<button onClick={handleCheckAll}>Check All</button> Lo que recorrería cada elemento y modificaría item.has_x a verdadero.
En los componentes secundarios, también hay un botón "Verificar", pero en lugar de verificar todos los elementos, solo verifica y establece que un elemento específico has_x como verdadero.
Creo que sabría cómo hacer cada uno. Para la función "Comprobar todo", crearía una instantánea, establecería el valor y luego, una vez que finalice el ciclo, establecería el estado. Para el botón secundario, realmente solo necesito un useState allí.
Sin embargo, estoy atascado en el botón "Verificar todo" porque me gustaría tener actualizaciones de ui como has_x para cada elemento actualizado y un tiempo de espera establecido, ya que la funcionalidad real de verificar todo será costosa y necesita alrededor de 200-300ms tiempo de espera por cada cheque. Imagine que el texto de un botón cambia a una marca de verificación a medida que la función recorre cada elemento.
Aquí está mi intento, pero la interfaz de usuario no se actualiza y solo configuro el estado una vez que está hecho:
const checkAllItems = () => { let temp = [...items]; temp.map((item, index) => { setTimeout(() => { let tempEl = {...tempState[index]}; if (tempEl) item.has_x = true; }, index * 200) }) setItems(temp) }Mi única idea de cómo hacer esto es usar referencias y recorrer las referencias para ejecutar una función en cada componente secundario que hará esto, pero creo que hay una forma correcta de hacerlo. ¿Como es posible?
No puedo imaginarme necesitando un tiempo de espera para actualizar el estado. Estoy seguro de que si modifica un poco su código de verificación de todos los elementos, no necesitará el tiempo de espera. Puede usar una actualización de estado funcional para poner en cola las actualizaciones de estado y actualizar correctamente desde el estado anterior en lugar del valor de estado cerrado en el ámbito de devolución de llamada.
const checkAllItems = () => { setItems(items => items.map(item => ({ ...item, has_x: true, }))); }; Esta copia superficial del estado de los items anteriores en una nueva matriz, y luego también copia superficialmente cada item elemento y actualiza la propiedad has_x .
Si está realizando solicitudes de API de back-end por actualización verificada en items , le sugiero que lo haga en un enlace de ciclo de vida de useEffect . Recorra cada item y ponga en cola la solicitud de red en un setTimeout . Básicamente, está dividiendo la lógica de tiempo de espera ( que tenía anteriormente ) de la actualización de estado.
useEffect(() => { items.forEach((item, index) => { setTimeout(() => { // make API request with `item` }, index * 200); }); }, [items]);/actualizar
Tampoco recomiendo que los componentes secundarios también tengan un estado "marcado", desea una única fuente de verdad en cuanto al estado marcado de su matriz de items . Pase una devolución de llamada a los elementos secundarios para que actualicen su estado verificado en el estado del componente principal.
Podría verse algo como esto:
const updateStatus = (key, value) => { setItems(items => items.map(item => item.key === key ? { ...item, has_x: value, } : item )); }; ... <Item key={item.key} hasX={item.has_x} updateX={updateStatus} />