Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

138
Vistas
Reaccionar useEffect no funciona como se esperaba

 useEffect(() => { const method = methodsToRun[0]; let results = []; if (method) { let paramsTypes = method[1].map(param => param[0][2]); let runAlgo = window.wasm.cwrap(method[0], 'string', paramsTypes); //this is emscripten stuff let params = method[1].map(param => document.getElementById(param[0][0]).value); let result = runAlgo(...params); //this runs the emscripten stuff results.push(...(JSON.parse(result))); setGlobalState('dataOutput', results); } let newMethodsToRun = methodsToRun.slice(1); if (methodsToRun.length>0) { setGlobalState('methodsToRun', newMethodsToRun); } } , [dataOutput, methodsToRun]);

Hola, estoy trabajando en una aplicación ReactJS que usa Webassembly con Emscripten. Necesito ejecutar una serie de algoritmos de Emscripten en mi Js y necesito mostrar los resultados a medida que llegan, no del todo al final. Algo como esto:

  • Ejecutar primer algoritmo
  • Mostrar resultados en pantalla desde el primer algoritmo
  • Ejecute el segundo algoritmo DESPUÉS de que los resultados del primer algoritmo se muestren en la pantalla (para que el usuario pueda seguir revisándolos)
  • Mostrar resultados en pantalla desde el segundo algoritmo...
  • y así

Ya probé un bucle que actualiza un estado global en cada iteración con tiempos de espera, etc., pero no tuve suerte, así que probé este enfoque usando useEffect, probé varias cosas pero los resultados siguen apareciendo todos juntos y no uno por uno. ¿Cualquier pista?

about 4 years ago · Santiago Gelvez
3 Respuestas
Responde la pregunta

0

Traté de burlarme de tu ejemplo AQUÍ :

 import React, { useState, useEffect } from 'react'; import './style.css'; export default function App() { const [methodsToRun, setMethodsToRun] = useState([method1, method2]); const [globalState, setGlobalState] = useState([]); useEffect(() => { if (methodsToRun.length <= 0) return; const method = methodsToRun[0]; let results = []; if (method) { let paramsTypes = method[1].map((param) => param[0][2]); let runAlgo = window.wasm.cwrap(method[0], 'string', paramsTypes); //this is emscripten stuff let params = method[1].map( (param) => document.getElementById(param[0][0]).value ); let result = runAlgo(...params); //this runs the emscripten stuff results.push(...JSON.parse(result)); setGlobalState((global) => [...global, results]); } setMethodsToRun((methods) => methods.slice(1)); }, [methodsToRun]); console.log('METHODS TO RUN', methodsToRun); console.log('GLOBAL RESULT', globalState); return ( <div> <div> Global state 1: {globalState[0] && globalState[0][0]}</div> <div> Global state 2: {globalState[1] && globalState[1][0]}</div> <div id="1">DIV 1 </div> <div id="4">DIV 2</div> <div id="7">DIV 3</div> </div> ); } const method1 = [ '1param0', [ ['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ], ]; const method2 = [ '2param0', [ ['11', '223', '3'], ['44', '55', '66'], ['77', '88', '99'], ], ]; //mock wasm window.wasm = { cwrap: (...args) => () => JSON.stringify(args), };

Este ejemplo asume que sus métodos wasm son sincrónicos, su DOM se actualizará y se volverá a representar con un nuevo globalState después de que se ejecute cada método, el ciclo está garantizado por el hecho de que está configurando una nueva matriz de métodos dividida por uno en el estado, que activará un rerender y una nueva ejecución de useEffect ya que tiene la matriz de métodos para ejecutar en la matriz methodsToRun . El bucle de procesamiento infinito se evita mediante la verificación if (methodsToRun.length <= 0) return; .

Sin embargo, el inconveniente de este enfoque es que si sus métodos wasms son sincrónicos y pesados, su interfaz de usuario se congelará hasta que regrese, y esa es una experiencia de usuario terrible para el usuario final. No estoy seguro de qué tipo de tarea está tratando de realizar allí, si se puede sincronizar y esperar (la lógica sería la misma) o si tiene que mover eso en un trabajador de servicio.

about 4 years ago · Santiago Gelvez Denunciar

0

Entonces, por lo que ha explicado aquí, creo que el problema se puede resolver de 2 maneras:

1 es con solicitudes/procesos sincrónicos.

Suponiendo que tiene 2 funciones (AlgoX y AlgoY) que desea ejecutar una tras otra, puede devolver la respuesta esperada. p.ej

 return AlgoX(); return AlgoY();

La palabra clave de retorno bloqueará la continuación del proceso en ejecución hasta que obtenga un resultado.

Otra alternativa que sugeriré será usar Self-Invoking-Expression:

 useEffect(() => { ( async function AlgoHandler(){ const method = methodsToRun[0]; let results = []; if (method) { let paramsTypes = method[1].map(param => param[0][2]); let runAlgo = await window.wasm.cwrap(method[0], 'string', paramsTypes); //this is emscripten stuff let params = method[1].map(param => document.getElementById(param[0][0]).value); let result = await runAlgo(...params); //this runs the emscripten stuff results.push(...(JSON.parse(result))); setGlobalState('dataOutput', results); } let newMethodsToRun = methodsToRun.slice(1); if (methodsToRun.length>0) { setGlobalState('methodsToRun', newMethodsToRun); } } )(); } , [dataOutput, methodsToRun]);

Observe dónde usé async y await en la segunda solución. Déjame saber si es útil.

about 4 years ago · Santiago Gelvez Denunciar

0

No estoy seguro de si esto responde a su pregunta, pero escribí un código de ejemplo que puede ayudarlo a satisfacer sus necesidades. Sin embargo, deberá modificarse para que se ajuste a su caso de uso, ya que esto debería considerarse un pseudocódigo:

 const initialState = { count: 0, results: [], }; function reducer(state, action) { switch (action.type) { case 'addResult': return { ...state, count: state.count + 1, results: [...state.results, action.result], }; default: return state; } } function Example({ methodsToRun }) { const [{ count, results }, dispatch] = useReducer(reducer, initialState); const next = useCallback(async() => { if(methodsToRun.length > count) { const result = await methodsToRun[count](); dispatch({ type: 'addResult', result }); } }, [count, methodsToRun]); useEffect(() => { next(); }, [next]); return ( <div> <p>Results:</p> <ol> {results.map(result => ( <li key={result/* choose a unique key from result here, do not use index */}>{result}</li> ))} </ol> </div> ); }

Básicamente, mi idea es crear una función de devolución de llamada, que en la primera ejecución será el método en el índice 0 en su conjunto de métodos. Cuando llegue el resultado, actualizará el estado con el resultado, así como también actualizará el contador.

El conteo actualizado hará que useCallback cambie al siguiente método en la matriz.

Cuando la devolución de llamada cambie, activará el efecto de uso y, de hecho, llamará a la función. Y así sucesivamente, hasta que no haya más métodos para ejecutar.

Tengo que admitir que no he intentado ejecutar este código, ya que me falta el contexto. Pero creo que debería funcionar.

about 4 years ago · Santiago Gelvez Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda