función setTimeout en saga React. js

Sólo quiero esconder Undo Button en UI después de 5 segundos. Aquí está mi código:

Saga.js

function* updateActionListingsSaga({ payload }) {
  try {
    const res = yield call(updateUnpublishedListingsById, payload);
    let unpublishedListings = yield select(UnpublishedListings);
    if (res) {
      const row = unpublishedListings.listingsData.results.find(data => data.id === res.ids[0])
      if (row) {
        row.review_status = payload.review_status
        row.isUndoEnabled = true;
        yield setTimeout(() => {row.isUndoEnabled = false}, 5000)
      }
    }
    
    yield put(updateActionListingSuccess());
  } catch (error) {
    yield put(apiError(error.error || error.message || error));
  }
}

Index.js

item?.isUndoEnabled && (
   handleUpdateListing(item?.id, 'pending')}
  />
)

Estoy recuperando una hilera en particular un Botón de Undo por pendiente row.isUndoEnabled= true propiedad y después de 5 segundos de retraso row.isUndoEnabled= false.

Producto real: La propiedad está establecida para Verdadero pero no oculta el botón

Salida esperada: Ocultar el botón

Espero la mejor respuesta. Gracias.

Pregunta hecha hace 3 años, 4 meses, 29 días - Por cyberjedi


3 Respuestas:

  • El botón no se esconde porque updateActionListingSuccess función se llama antes de que se ejecute el callback timeout. Le recomiendo:

    1. Wrap the timeout función dentro de Promise y espera hasta que termine.
    2. Call updateActionListingSuccess justo después de la promesa se resuelve.
        function* updateActionListingsSaga({ payload }) {
          try {
            const res = yield call(updateUnpublishedListingsById, payload);
            let unpublishedListings = yield select(UnpublishedListings);
            let row = null;
            if (res) {
              row = unpublishedListings.listingsData.results.find(
                data => data.id === res.ids[0]
              );
              if (row) {
                row.review_status = payload.review_status;
                row.isUndoEnabled = true;
              }
            }
            yield put(updateActionListingSuccess());
            if (row) {
              yield new Promise(resolve =>
                setTimeout(() => {
                  row.isUndoEnabled = false;
                  resolve();
                }, 5000)
              );
            }
            yield put(updateActionListingSuccess()); // update again
          } catch (error) {
            yield put(apiError(error.error || error.message || error));
          }
        }
    
    

    Respondida el Dec 17, 2020 a las 12:36 - por gitguru

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás experimentando es que setTimeout no se puede usar directamente dentro de una función generadora de saga de Redux. En su lugar, debes usar una función delay proporcionada por redux-saga.

    Aquí tienes una forma de hacerlo correctamente:

    javascript
    import { delay } from 'redux-saga/effects';
    
    function* updateActionListingsSaga({ payload }) {
      try {
        const res = yield call(updateUnpublishedListingsById, payload);
        let unpublishedListings = yield select(UnpublishedListings);
        if (res) {
          const row = unpublishedListings.listingsData.results.find(data => data.id === res.ids[0])
          if (row) {
            row.review_status = payload.review_status
            row.isUndoEnabled = true;
            yield delay(5000); // Esperar 5 segundos
            row.isUndoEnabled = false;
          }
        }
    
        yield put(updateActionListingSuccess());
      } catch (error) {
        yield put(apiError(error.error || error.message || error));
      }
    }
    

    De esta manera, delay(5000) provocará que Saga espere 5 segundos antes de continuar con el siguiente paso de la saga, en lugar de usar directamente setTimeout.

    Espero que esta solución te ayude a lograr el comportamiento esperado de ocultar el botón después de 5 segundos. ¡Déjame saber si tienes alguna otra pregunta!

    Respondida el Dec 18, 2020 a las 12:37 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Parece que hay un problema con tu uso de la función setTimeout dentro de la saga. Aquí tienes el código corregido:

    ```js function updateActionListingsSaga({ payload }) { try { const res = yield call(updateUnpublishedListingsById, payload); let unpublishedListings = yield select(UnpublishedListings); if (res) { const row = unpublishedListings.listingsData.results.find(data => data.id === res.ids[0]) if (row) { row.reviewstatus = payload.reviewstatus row.isUndoEnabled = true;

        // setTimeout() no puede usarse dentro de un generador de saga.
        // En su lugar, usa `delay()`.
        yield delay(5000);
        row.isUndoEnabled = false;
      }
    }
    
    yield put(updateActionListingSuccess());
    

    } catch (error) { yield put(apiError(error.error || error.message || error)); } } ```

    Cambios realizados:

    He reemplazado setTimeout con delay de la librería redux-saga/effects. delay es una función de efecto que permite pausar la ejecución de la saga durante un intervalo de tiempo especificado. He movido la declaración yield delay(5000); fuera del bloque if (row). Esto asegura que el retraso se aplique incluso si row no está definido.

    Cómo funciona ahora:

    Cuando se llame a la saga updateActionListingsSaga, actualizará la propiedad isUndoEnabled de la fila correspondiente a true. Después de un retraso de 5 segundos, la saga actualizará isUndoEnabled a false utilizando el efecto delay. Esto hará que el botón Deshacer desaparezca de la interfaz de usuario después de 5 segundos.

    Nota:*

    Asegúrate de importar delay desde redux-saga/effects en la parte superior de tu saga.

    js
    import { delay } from 'redux-saga/effects';
    

    Respondida el Dec 18, 2020 a las 12:45 - por Gemini

    Votos positivos: 0 | Votos negativos: 0