Estoy tratando de llenar una matriz con varias matrices de objetos, pero en la primera representación, los valores se rellenan de forma inversa dentro de la matriz y, después de actualizar, vuelven a ser como deberían.


  const getProducts = async (data) => {
    await productServices
      .getProductsByTakeoffWizardStep(data)
      .then((response) => {
        setRows((rows) => [...rows, response.data]);
      })
      .catch((error) => {
        console.log(error.response);
      });
  };

  const getTakeoffIDs = () => {
    var i = 1;
    takeoffServices
      .getTakeoffSteps(5)
      .then((response) => {

        response.data.forEach((element) => {
          setSteps((steps) => [...steps, element.description]);
          setStepsID((stepsID) => [...stepsID, element.stepID]);
          var data = { StepID: element.stepID, TakeoffID: 4 };
          getProducts(data);
          setStepSequence((stepSequence) => [
            ...stepSequence,
            "Step " + i + "",
          ]);
          i = i + 1;
        });
      })
      .catch((error) => {
        console.log(error.response);
      });
  };

  useEffect(() => {
    setSteps([]);
    setStepsID([]);
    setRows([]);
    getTakeoffIDs();
  }, []);

Entonces, en el primer renderizado, la matriz se ve así

(2) [Array(1), Array(2)]
0: Array(1)
0: {product: {…}, quantity: null}
length: 1
[[Prototype]]: Array(0)
1: Array(2)
0: {product: {…}, quantity: null}
1: {product: {…}, quantity: null}
length: 2
[[Prototype]]: Array(0)
length: 2
[[Prototype]]: Array(0)

Y después de actualizar la página se ve así

(2) [Array(2), Array(1)]
0: Array(2)
0: {product: {…}, quantity: null}
1: {product: {…}, quantity: null}
length: 2
[[Prototype]]: Array(0)
1: Array(1)
0: {product: {…}, quantity: null}
length: 1
[[Prototype]]: Array(0)
length: 2
[[Prototype]]: Array(0)

¿Qué podría estar causando esto y qué puedo hacer para solucionarlo?

Estoy accediendo a la página usando history.push () desde otra página, pero ninguno de los estados que estoy pasando afecta el proceso de búsqueda, solo la visualización de algunos párrafos no relacionados con los datos que estoy obteniendo.

0
Selim Choueiter 24 nov. 2021 a las 11:34
¿puedes darme mas detalles? o el contexto.
 – 
LHDi
24 nov. 2021 a las 11:37
Estoy tratando de acceder a la página usando history.push () desde una tabla donde, dependiendo de la fila de la tabla, estoy obteniendo datos. Sin embargo, cuando entro a la página, recibo los datos en orden inverso, por lo que los datos que se supone que están en la página 1 se muestran en la página 2 y viceversa. Cuando usé console.log en el estado "filas" que contiene los valores, me di cuenta de que los valores en la matriz se estaban insertando en orden inverso. La respuesta.data en la función getProducts es la matriz que estoy completando en la matriz inicial que depende de los valores obtenidos de getTakeoffIDs.
 – 
Selim Choueiter
24 nov. 2021 a las 11:41
Las solicitudes ajax, como la mayoría de las tareas asíncronas, pueden resolverse en cualquier orden aleatorio.
 – 
Thomas
24 nov. 2021 a las 11:57
Utilicé este método en varias páginas y funcionó perfectamente para todas. La única diferencia en esta página es que llamé a una función que recupera (getProducts) de la base de datos varias veces.
 – 
Selim Choueiter
24 nov. 2021 a las 12:01
Sí, envía varias solicitudes al servidor y pueden regresar en cualquier orden arbitrario. Debido a la latencia en una conexión en particular, algún GC, algún mecanismo de bloqueo o un millón de otras razones. Las solicitudes posteriores no esperarán a que termine la anterior antes de responder.
 – 
Thomas
24 nov. 2021 a las 12:11

1 respuesta

La mejor respuesta

Así es como escribiría esto:

const getProduct = async (data) => {
  try {
    const response = await productServices.getProductsByTakeoffWizardStep(data);
    return response.data;
  } catch (error) {
    console.log(error.response);
  }
}

const getTakeoffIDs = () => {
  takeoffServices
    .getTakeoffSteps(5)
    .then(async (response) => {

      // try moving setSteps(), setStepsID() and setStepSequence() up here, so they don't wait for the products.

      const products = await Promise.all(
        response.data.map(element => getProduct({
          StepID: element.stepID,
          TakeoffID: 4
        }))
      );

      setRows((rows) => [
        ...rows,
        ...products
      ]);
      setSteps((steps) => [
        ...steps,
        ...response.data.map(element => element.description)
      ]);
      setStepsID((stepsID) => [
        ...stepsID,
        ...response.data.map(element => element.stepID)
      ]);
      setStepSequence((stepSequence) => [
        ...stepSequence,
        ...response.data((_, i) => `Step ${i + 1}`)
      ]);
    })
    .catch((error) => {
      console.log(error.response);
    });
};


useEffect(() => {
  setSteps([]);
  setStepsID([]);
  setRows([]);
  getTakeoffIDs();
}, []);
  • En lugar de llamar a todos estos setState() s varias veces, Array.map() los datos y los agrego todos a la vez.
  • await para todas las getProduct() llamadas para finalizar y también enviarlas a la vez; en orden.

Lo único de lo que no estoy seguro es si desea que el setRows() se llame junto con el otro establecedor, o si los otros deben ir primero (porque los datos están disponibles) y setRows() deben ser llamado más tarde, tan pronto como los datos estén disponibles.

0
Thomas 24 nov. 2021 a las 12:32
El número de matrices dentro de las filas generalmente depende del número de valores recibidos de la base de datos dentro de la función getTakeoffSteps. Por lo tanto, habrá la misma cantidad de matrices dentro de las filas que en los otros estados, pero no necesariamente dependen unas de otras. Probé tu respuesta y funcionó. Gracias
 – 
Selim Choueiter
24 nov. 2021 a las 12:37