One place for hosting & domains

      funcionan

      Cómo funcionan las acciones asíncronas de Redux con Redux Thunk


      Introducción

      De forma predeterminada, las acciones de Redux se envían de forma síncrona, lo cual es un problema para cualquier aplicación no trivial que necesite comunicarse con una API externa o realizar efectos secundarios. Redux también admite el middleware que se encuentra entre la acción que se envía y la acción que llega a los reductores.

      Hay dos bibliotecas muy populares de middleware que permiten efectos secundarios y acciones asíncronas: Redux Thunk y Redux Saga. En este artículo, aprenderá sobre Redux Thunk.

      Thunk es un concepto de programación donde se utiliza una función para retrasar la evaluación o el cálculo de una operación.

      Redux Thunk es un middleware que le permite invocar creadores de acciones que devuelven una función en vez de un objeto de acción. Esa función recibe el método de envío de la tienda, que luego se utiliza para enviar acciones síncronas regulares dentro del cuerpo de la función una vez que se completaron las operaciones asíncronas.

      En este artículo, aprenderá cómo agregar Redux Thunk y cómo puede integrarse en una aplicación de tareas pendientes hipotética.

      Requisitos previos

      En esta artículo, se asume que tiene algunos conocimientos básicos de React y Redux. Puede consultar este artículo si recién está comenzando a usar Redux.

      Este tutorial se basa en una aplicación de tareas pendientes hipotética que rastrea las tareas que se deben realizar y completar. Podemos suponer que create-react-app se utilizó para generar una nueva aplicación React y que redux, react-redux y axios ya se instalaron.

      Aquí no se explica en detalle cómo crear una aplicación de tareas pendientes desde cero. Se presenta como un contexto conceptual para resaltar Redux Thunk.

      Cómo agregar redux-thunk

      Primero, utilice el terminal para navegar al directorio del proyecto e instalar el paquete redux-thunk en su proyecto:

      • npm install redux-thunk@2.3.0

      Nota: Redux Thunk solo tiene 14 líneas de código. Verifique el origen aquí para saber cómo funciona un middleware de Redux más de cerca.

      Ahora aplique el middleware cuando cree la tienda de su aplicación usando applyMiddleware de Redux. Dada una aplicación React con redux y react-redux, su archivo index.js podría verse así:

      src/index.js

      import React from 'react';
      import ReactDOM from 'react-dom';
      import { Provider } from 'react-redux';
      import { createStore, applyMiddleware } from 'redux';
      import thunk from 'redux-thunk';
      import './index.css';
      import rootReducer from './reducers';
      import App from './App';
      import * as serviceWorker from './serviceWorker';
      
      // use applyMiddleware to add the thunk middleware to the store
      const store = createStore(rootReducer, applyMiddleware(thunk));
      
      ReactDOM.render(
        <Provider store={store}>
          <App />
        </Provider>,
        document.getElementById('root')
      );
      

      Ahora, importó y aplicó Redux Thunk en su aplicación.

      Cómo usar Redux Thunk en una aplicación de muestra

      Redux Thunk se usa con mayor frecuencia para comunicarse de manera asíncrona con una API externa y, así, recuperar o guardar datos. Redux Thunk facilita el envío de acciones que siguen el ciclo de vida de una solicitud a una API externa.

      Normalmente, crear un nuevo elemento de tarea implica enviar primero una acción para indicar que se inició la creación de un elemento de tarea. Luego, si el elemento de tarea se crea correctamente y el servidor externo lo devuelve, se envía otra acción con el nuevo elemento de tarea. En el caso de que se produzca un error y la tarea no se guarde en el servidor, se puede enviar una acción con el error.

      Veamos cómo se puede hacer esto usando Redux Thunk.

      En el componente de su contenedor, importe la acción y envíela:

      src/containers/AddTodo.js

      import { connect } from 'react-redux';
      import { addTodo } from '../actions';
      import NewTodo from '../components/NewTodo';
      
      const mapDispatchToProps = dispatch => {
        return {
          onAddTodo: todo => {
            dispatch(addTodo(todo));
          }
        };
      };
      
      export default connect(
        null,
        mapDispatchToProps
      )(NewTodo);
      

      La acción usará Axios para enviar una solicitud POST al punto de conexión de JSONPlaceholder (https://jsonplaceholder.typicode.com/todos):

      src/actions/index.js

      import {
        ADD_TODO_SUCCESS,
        ADD_TODO_FAILURE,
        ADD_TODO_STARTED,
        DELETE_TODO
      } from './types';
      
      import axios from 'axios';
      
      export const addTodo = ({ title, userId }) => {
        return dispatch => {
          dispatch(addTodoStarted());
      
          axios
            .post(`https://jsonplaceholder.typicode.com/todos`, {
              title,
              userId,
              completed: false
            })
            .then(res => {
              dispatch(addTodoSuccess(res.data));
            })
            .catch(err => {
              dispatch(addTodoFailure(err.message));
            });
        };
      };
      
      const addTodoSuccess = todo => ({
        type: ADD_TODO_SUCCESS,
        payload: {
          ...todo
        }
      });
      
      const addTodoStarted = () => ({
        type: ADD_TODO_STARTED
      });
      
      const addTodoFailure = error => ({
        type: ADD_TODO_FAILURE,
        payload: {
          error
        }
      });
      

      Observe cómo el creador de la acción addTodo devuelve una función, en lugar del objeto de la acción regular. Esa función recibe el método de envío de la tienda.

      Dentro del cuerpo de la función, primero envíe una acción síncrona inmediata a la tienda para indicar que empezó a guardar la tarea con la API externa. Luego, realice la solicitud POST real al servidor usando Axios. En caso de una respuesta exitosa del servidor, enviará una acción de éxito síncrona con los datos recibidos de la respuesta, pero, en caso de una respuesta fallida, enviará una acción síncrona diferente con el mensaje de error.

      Cuando se utiliza una API externa, como JSONPlaceholder en este caso, se puede ver el retraso real de la red. Sin embargo, si está trabajando con un servidor de backend local, las respuestas de la red pueden pasar demasiado rápido para experimentar el retraso de la red que experimentaría un usuario real, por lo que puede añadir un retraso artificial al desarrollar:

      src/actions/index.js

      // ...
      
      export const addTodo = ({ title, userId }) => {
        return dispatch => {
          dispatch(addTodoStarted());
      
          axios
            .post(ENDPOINT, {
              title,
              userId,
              completed: false
            })
            .then(res => {
              setTimeout(() => {
                dispatch(addTodoSuccess(res.data));
              }, 2500);
            })
            .catch(err => {
              dispatch(addTodoFailure(err.message));
            });
        };
      };
      
      // ...
      

      Para probar los escenarios de error, puede lanzar un error manualmente:

      src/actions/index.js

      // ...
      
      export const addTodo = ({ title, userId }) => {
        return dispatch => {
          dispatch(addTodoStarted());
      
          axios
            .post(ENDPOINT, {
              title,
              userId,
              completed: false
            })
            .then(res => {
              throw new Error('addToDo error!');
              // dispatch(addTodoSuccess(res.data));
            })
            .catch(err => {
              dispatch(addTodoFailure(err.message));
            });
        };
      };
      
      // ...
      

      Para completar, aquí hay un ejemplo de cómo se vería el reductor de tareas para manejar el ciclo de vida completo de la solicitud:

      src/reducers/todosReducer.js

      import {
        ADD_TODO_SUCCESS,
        ADD_TODO_FAILURE,
        ADD_TODO_STARTED,
        DELETE_TODO
      } from '../actions/types';
      
      const initialState = {
        loading: false,
        todos: [],
        error: null
      };
      
      export default function todosReducer(state = initialState, action) {
        switch (action.type) {
          case ADD_TODO_STARTED:
            return {
              ...state,
              loading: true
            };
          case ADD_TODO_SUCCESS:
            return {
              ...state,
              loading: false,
              error: null,
              todos: [...state.todos, action.payload]
            };
          case ADD_TODO_FAILURE:
            return {
              ...state,
              loading: false,
              error: action.payload.error
            };
          default:
            return state;
        }
      }
      

      Para qué sirve getState

      Además de recibir el método de envío del estado, la función devuelta por un creador de acciones asíncronas con Redux Thunk también recibe el método getState de la tienda, por lo que los valores actuales de la tienda se pueden ver así:

      src/actions/index.js

      export const addTodo = ({ title, userId }) => {
        return (dispatch, getState) => {
          dispatch(addTodoStarted());
      
          console.log('current state:', getState());
      
          // ...
        };
      };
      

      Al hacer lo que se menciona arriba, el estado actual simplemente se imprimirá en la consola.

      Por ejemplo:

      {loading: true, todos: Array(1), error: null}
      

      Usar getState puede ser útil para manejar las cosas de manera diferente según el estado actual. Por ejemplo, si desea limitar la aplicación a solo cuatro elementos de tareas a la vez, puede regresar de la función si el estado ya contiene la cantidad máxima de elementos de tareas:

      src/actions/index.js

      export const addTodo = ({ title, userId }) => {
        return (dispatch, getState) => {
          const { todos } = getState();
      
          if (todos.length > 4) return;
      
          dispatch(addTodoStarted());
      
          // ...
        };
      };
      

      Al hacer lo que se menciona arriba, la aplicación se limitará a cuatro elementos de tareas.

      Conclusión

      En este tutorial, aprendió a agregar Redux Thunk a una aplicación React para permitir el envío de acciones de forma asíncrona. Esto es práctico cuando se utiliza una tienda de Redux y API externas.

      Si desea aprender más sobre React, eche un vistazo a nuestra serie Cómo crear código en React.js, o consulte nuestra página del tema React para ver ejercicios y proyectos de programación.



      Source link

      Cómo funcionan los enlaces de ciclo de vida de Vue.js


      Introducción

      Los enlaces de ciclo de vida son una ventana para ver cómo la biblioteca que está usando funciona en segundo plano. Los enlaces de ciclo de vida le permiten saber cuándo se crea su componente, se añade al DOM, se actualiza o se destruye.

      Este diagrama de la documentación oficial de Vue.js captura el ciclo de vida de la instancia Vue.js:

      Diagrama del ciclo de vida de la instancia Vue.js

      Este artículo le explicará los enlaces de creación, montaje, actualización y destrucción.

      Cómo funcionan los enlaces de creación (inicialización)

      Los enlaces de creación son los primeros enlaces que se ejecutan en su componente. Le permiten realizar acciones antes de que su componente haya sido añadido al DOM. A diferencia de cualquier otro enlace, los enlaces de creación también se ejecutan durante la renderización del lado del servidor.

      Utilice los enlaces de creación si necesita configurar cosas en su componente, durante la renderización del cliente y la renderización del servidor.

      No tendrá acceso al DOM o al elemento de montaje objetivo (this.$el) dentro de los enlaces de creación.

      beforeCreate

      El enlace beforeCreate se ejecuta en el momento de inicializar su componente. Los datos no se han hecho reactivos y los eventos no se han configurado aún:

      ExampleComponent.vue

      <script>
      export default {
        beforeCreate() {
          console.log('At this point, events and lifecycle have been initialized.')
        }
      }
      </script>
      

      En este ejemplo, cuando el enlace beforeCreate se ejecuta, este fragmento de código registrará el mensaje: en este momento, los eventos y el ciclo de vida se han inicializado.

      created

      Puede acceder a los datos reactivos y a los eventos que están activos con el enlace created. Las plantilla y Virtual DOM no han sido montados aún o renderizados:

      ExampleComponent.vue

      <template>
        <div ref="example-element">{{ propertyComputed }}</div>
      </template>
      
      <script>
      export default {
        data() {
          return {
            property: 'Example property.'
          }
        },
      
        computed: {
          propertyComputed() {
            return this.property
          }
        },
      
        created() {
          console.log('At this point, this.property is now reactive and propertyComputed will update.')
          this.property = 'Example property updated.'
        }
      }
      </script>
      

      En este ejemplo, el fragmento de código almacenará property como Example property. Cuando se ejecuta el enlace created, se registrará un mensaje de At this point, this.property is now reactive and propertyComputed will update. y, luego, property se cambia a Example property updated.

      Más adelante en el ciclo de vida, {{ propertyComputed }} aparecerá como Example property updated, en vez de como Example property.

      En este paso, ha revisado algunos ejemplos de enlaces de creación y está listo para pasar a la siguiente parte del ciclo de vida, los enlaces de montaje.

      Cómo funcionan los enlaces de montaje (inserción DOM)

      Los enlaces de montaje a menudo son los enlaces más usados. Le permiten acceder a su componente inmediatamente antes y después de la primera renderización. Sin embargo, no se ejecutan durante la renderización del lado del servidor.

      Utilice enlaces de montaje si necesita acceder o modificar el DOM de su componente inmediatamente antes o después de la renderización inicial.

      No utilice los enlaces de montaje si necesita obtener algunos datos para su componente durante la inicialización.

      Nota: Utilice created (o created y activated para los componentes de keep-alive) para esto. Especialmente si necesita esos datos durante la renderización del lado del servidor.

      beforeMount

      El enlace beforeMount se ejecuta justo antes de que se produzca la renderización inicial y tras compilarse las funciones de plantilla o renderización:

      ExampleComponent.vue

      <script>
      export default {
        beforeMount() {
          console.log(`At this point, vm.$el has not been created yet.`)
        }
      }
      </script>
      

      En este ejemplo, cuando se ejecuta el enlace beforeMount, este fragmento de código registrará el mensaje: At this point, vm.$el has not been created yet..

      mounted

      En el enlace mounted, tendrá acceso completo al componente reactivo, las plantillas y DOM renderizado (a través de this.$el).

      Utilice mounted para modificar el DOM, sobre todo cuando integra bibliotecas no Vue:

      ExampleComponent.vue

      <template>
        <div ref="example-element">Example component.</div>
      </template>
      
      <script>
      export default {
        mounted() {
          console.log(`At this point, vm.$el has been created and el has been replaced.`);
          console.log(this.$el.textContent) // Example component.
        }
      }
      </script>
      

      En este ejemplo, cuando se ejecuta el enlace mounted, este fragmento de código registrará el mensaje At this point, vm.$el has been created and el has been replaced.. Además, se registrará un mensaje de Contenido de ejemplo (this.$el.textContent).

      En esta sección, exploró casos de uso para los enlaces de montaje. En el siguiente paso, revisó algunos ejemplos que usan los enlaces de actualización.

      Comprender los enlaces de actualización (Diff y Re-render)

      Los enlaces de actualización se invocan siempre que una propiedad reactiva usada por su componente cambie u otra cosa haga que se vuelva a renderizar. Le permiten engancharse al ciclo watch-compute-render para su componente.

      Utilice los enlaces de actualización si necesita saber cuándo se vuelve a renderizar su componente, quizá para depurar o perfilar.

      No utilice ganchos de actualización si necesita saber cuándo cambia una propiedad reactiva en su componente. Utilice propiedades computadas o vigilantes para eso.

      beforeUpdate

      El enlace beforeUpdate se ejecuta cuando los datos cambian en su componente, y el ciclo de actualización se inicia, justo antes de que el DOM se corrija y vuelva a renderizar.

      Utilice beforeUpdate si necesita obtener el nuevo estado de cualquier dato reactivo en su componente antes de que se renderice realmente.

      ExampleComponent.vue

      <template>
        <div ref="example-element">{{counter}}</div>
      </template>
      
      <script>
      export default {
        data() {
          return {
            counter: 0
          }
        },
      
        created() {
          setInterval(() => {
            this.counter++
          }, 1000)
        },
      
        beforeUpdate() {
          console.log(`At this point, Virtual DOM has not re-rendered or patched yet.`)
          // Logs the counter value every second, before the DOM updates.
          console.log(this.counter)
        }
      }
      </script>
      

      Primero, este fragmento de código guardará counter como 0. Cuando se ejecute el enlace created, aumentará counter cada 1000 ms. Cuando el enlace beforeUpdate se ejecuta, este fragmento de código registrará el mensaje: En este momento, Virtual DOM no se ha vuelto a renderizar ni se ha parcheado y se registra un número para counter,

      updated

      El enlace updated se ejecuta cuando cambian los datos en su componente y el DOM se vuelve a renderizar.

      Use updated si necesita acceder al DOM tras cambiar una propiedad:

      ExampleComponent.vue

      <template>
        <div ref="example-element">{{counter}}</div>
      </template>
      
      <script>
      export default {
        data() {
          return {
            counter: 0
          }
        },
      
        created() {
          setInterval(() => {
            this.counter++
          }, 1000)
        },
      
        updated() {
          console.log(`At this point, Virtual DOM has re-rendered and patched.`)
          // Fired every second, should always be true
          console.log(+this.$refs['example-element'].textContent === this.counter)
        }
      }
      </script>
      

      Primero, este fragmento de código guardará counter como 0. Cuando el enlace created se ejecute, incrementará counter cada 1000 ms. Cuando se ejecuta el enlace updated, este fragmento de código registrará el mensaje: En este momento, Virtual DOM se ha vuelto a renderizar y parcheado y se registra un valor booleano de true porque el valor renderizado y el valor actual con iguales.

      Ahora que ha explorado el uso de los enlaces de actualización, está listo para aprender sobre los enlaces de destrucción.

      Comprender los enlaces de destrucción (Desmontaje)

      Los enlaces de destrucción le permiten realizar acciones cuando se destruye su componente, como la limpieza o el envío de análisis. Se activan cuando su componente se desmonta y elimina del DOM.

      beforeDestroy

      beforeDestroy se activa justo antes del desmontaje. Su componente seguirá estando completamente presente y funcional.

      Utilice beforeDestroy si necesita limpiar eventos o suscripciones reactivas:

      ExampleComponent.vue

      <script>
      export default {
        data() {
          return {
            exampleLeakyProperty: 'This represents a property that will leak memory if not cleaned up.'
          }
        },
      
        beforeDestroy() {
          console.log(`At this point, watchers, child components, and event listeners have not been teared down yet.`)
          // Perform the teardown procedure for exampleLeakyProperty.
          // (In this case, effectively nothing)
          this.exampleLeakyProperty = null
          delete this.exampleLeakyProperty
        }
      }
      </script>
      

      Este fragmento de código primero almacenará exampleLeakyProperty. Cuando el enlace beforeDestroy se ejecuta, este fragmento de código registrará el mensaje En este momento, los vigilantes, componentes secundarios y oyentes de eventos no hay sido desmontados aún y luego se elimina exampleLeakyProperty.

      destroyed

      Cuando llegue al enlace destroyed, su componente estará prácticamente vacío. Todo lo que estaba unido a él se ha destruido.

      Utilice destroyed si necesita realizar cualquier limpieza de último minuto o informar a un servidor remoto que el componente se ha destruido.

      ExampleComponent.vue

      <script>
      import ExampleAnalyticsService from './example-analytics-service'
      
      export default {
        destroyed() {
          console.log(`At this point, watchers, child components, and event listeners have been torn down.`)
          console.log(this)
          ExampleAnalyticsService.informService('Component destroyed.')
        }
      }
      </script>
      

      Primero, este fragmento de código importará ExampleAnalyticsService. Cuando se ejecute el enlace beforeDestroy, este fragmento de código registrará el mensaje At this point, watchers, child components, and event listeners have been torn down.. Lo que queda del componente se registrará en la consola y a ExampleAnalyticsService se pasará el mensaje Componente destruido.

      Con eso, completó su revisión general de los enlaces de ciclo de vida de Vue.js.

      Otros enlaces

      Hay otros dos enlaces, activated y deactivated. Estos son para los componentes keep-alive, un tema que está fuera del alcance de este artículo.

      Es suficiente decir que le permiten detectar cuando un componente que está envuelto en una etiqueta <keep-alive><keep-alive> se activa o desactiva. Es posible que los use para buscar datos para su componente o administrar los cambios de estado, comportándose de forma efectiva como created y beforeDestroy sin la necesidad de realizar una reconstrucción completa del componente.

      Conclusión

      En este artículo, hemos explicado los diferentes enlaces de ciclo de vida disponibles en el ciclo de vida de la instancia Vue.js. Ha explorado los diferentes casos de uso para los enlaces de creación, los enlaces de montaje, los enlaces de actualización y los enlaces de destrucción.

      Si desea saber más sobre Vue.js, consulte nuestra página del tema Vue.js para consultar ejercicios y proyectos de programación.



      Source link