No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Middlewares

11/22
Recursos

Aportes 25

Preguntas 4

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Este es el middleware que se me ocurri贸: Agregar el prefijo 鈥淧oke :鈥 al nombre de cada pokemon.

export const prefix = store => next => action => {
    const prefixed = action.action.payload.map( pokemon => ({
        ...pokemon,
        name: 'Poke: ' + pokemon.name
    }) )

    const updatedAction = {
        ...action,
        action: {...action.action, payload: prefixed}
    }
    next(updatedAction);
}

Creo que ha esto se refer铆a la profesora cuando menciona que la curva de aprendizaje es m谩s pronunciada en Redux comparada a Context API. La sintaxis del middleware me parece bien complicada: una funci贸n que recibe como argumento otra funci贸n la cual a su vez devuelve otra funci贸n鈥 y creo que all铆 termina. Seguro que la puedo memorizar pero me interesa m谩s entenderla. 驴Ser铆a equivalente a escribir lo siguiente?:


export const logger = function(store) {
	return function(next) {
		return function(action) {
  			console.log(action);
  			next(action);
		};
	};
};

Para los que no entendieron el concepto de Currying functions aqu铆 un art铆culo, obviamente en ingl茅s como lo est谩 el 99.999% de la informaci贸n en internet:

https://javascript.info/currying-partials

Mi middleware personalizado fue agregarle un numero indexado a cada pokemon. Aqui el codigo

export const number = (store) => (next) => (action) => {
    let arrayPokeWithNumber = [...action.action.payload] 
    for (let i = 0 ; i < arrayPokeWithNumber.length; i++) {
        arrayPokeWithNumber[i].name = `${[i]} - ${arrayPokeWithNumber[i].name}` 
    }
    const newFeature = {
        ...action,
        action:{...action.action, payload: arrayPokeWithNumber}
    }
    next(newFeature)
}

Middleware para invertir el nombre de los pokemones 馃槂

export const reversed = (store) => (next) => (action) => {
    const reversedPkm = action.action.payload.map((item) => {
        const split = item.name.split('');
        const reverseArray = split.reverse();
        const joinArray = reverseArray.join('');

        return { ...item, name: joinArray };
    });

    const updated = { ...action, action: { ...action.action, payload: reversedPkm } };

    next(updated);
};

Para qui茅n venga con TS, le dejo el c贸digo que a m铆 me ha funcionado. Reconozco que ha faltado tipar algunas cosas, pero es porque lo estoy practicando.
.
En este caso, me cost;o entender que lo que aparece en el video, no es lo mismo a la respuesta que me estaba dando en consola cuando se mostraba informaci贸n en el logger. Ac谩 dejo el resultado:

// ** index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { pokemonsReducer } from './reducers/pokemons';
import { Provider } from 'react-redux';
import { applyMiddleware, compose, legacy_createStore as createStore } from 'redux';
import { featuring, logger } from './middlewares';
import './index.css';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

const composedEnhancers = compose(
  applyMiddleware(logger, featuring),
  (window as any).__REDUX_DEVTOOLS_EXTENSION__ && (window as any).__REDUX_DEVTOOLS_EXTENSION__(),
)

const store = createStore(pokemonsReducer, composedEnhancers);

root.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>
);

.

// ** Middlewares/index.ts

export const logger = (store: any) => {   // store de la aplicaci贸n
  return (next: any) => {          // next es una funci贸n que se llama cuando el middleware termina su trabajo y env铆a el action al reducer
    return (action: any) => {      // action es la informaci贸n que se pasa al reducer
      console.log(action);
      next(action); // <-- hace que el action llegue al reducer
    } 
  }
};

export const featuring = (store: any) => {
  return (next: any) => {
    return (actionNew: any) => {
      debugger;
      const featured = [
        { name: 'Momea', url: 'https://ab.c' }, // <-- nuevo pokemon que quiero meter al state
        ...actionNew.payload, // <-- desestructura todos los pokemons que est谩n en el payload de 'action'
      ];
      const updatedAction = {
        ...actionNew,
        payload: [
          ...featured,
        ]
      }
      next(updatedAction);
    } 
  }
};

No tengo el mismo objeto, por eso en el middleware cambi茅 la forma de desestructurar todo el array

la funcionalidad de mi middleware personalizado fue ordenar el arreglo de pokemones en orden alfab茅tico a partir de la propiedad name de cada uno

export const myMiddleware = (store) => (next) => (actionInfo) => {
    const alphabetPokemon = actionInfo.action.payload.map(poke => poke.name).sort()
    const pokemonPayload = actionInfo.action.payload.map((poke, index) => ({ ...poke, name: alphabetPokemon[index] }))

    const myFormatPokemon = {
        ...actionInfo,
        action: { ...actionInfo.action, payload: pokemonPayload}       
    }

    // console.log(myFormatPokemon)
    next(myFormatPokemon)
}

Middlewares:
Es una pieza de c贸digo que se ejecuta cuando X recibe un request y ese mismo X da respuesta al request.

Ayuda a los desarrolladores a dise帽ar aplicaciones con mayor eficiencia. Adem谩s, act煤a como hilo conductor entre las aplicaciones, los datos y los usuarios.

Los podemos usar para:

  • Hacer logs de errores

  • Hacer fetch de data

  • Depurar nuestra aplicaci贸n

  • Tambi茅n podemos customizar nuestra data con applyMiddleware

Agregue una nueva propiedad dentro del arreglo de pokemons con el numero del pokemon con el formato #001

export const enumerated = (store) => (next) => (action) => {
    const list = [ ...action.action.payload];    
    const listUpdated = [];
    let count = 0;    
    list.forEach( (pokemon) => listUpdated.push({...pokemon, number: "#" + (++count).toString().padStart(3,'0') }));
    const updatedAction = {...action, action: {...action.action, payload: listUpdated}}
    next(updatedAction);
};

Si est谩n trabajando con ts, encontr茅 esta soluci贸n y, hasta el momento parece funcionar
https://www.npmjs.com/package/redux-devtools-extension

Hice un middleware que pone la primera letra del nombre del Pok茅mon en may煤scula.

export const nameUpperCase = (store) => (next) => (actionInfo) => {

    const featured = [
         ...actionInfo.action.payload.map(
            pokemon => ({
                ...pokemon,
                 name: pokemon.name.charAt(0).toUpperCase() + 
                        pokemon.name.slice(1)
            })
        )
    ]

    const updateActionInfo = {
        ...actionInfo,
        action: {
            ...actionInfo.action,
            payload: featured
        }
    }
    next(updateActionInfo)
}

MI middleware que agrega un valor aleatorio de poder para cada pokemon

export const addPower = (store: any) => (next: any) => (actionInfo: any) => {

  const featured = actionInfo.payload.map((e: any) => ({ ...e, "power": Math.floor(Math.random() * 100) + 1 }))
  const updatedAction = {
    ...actionInfo, payload: featured
  }
  next(updatedAction)
}

mi middleware

Reto del Middleware:

Poner los nombres de los pokemos en may煤scula:

隆Y este fue el resultado! 馃帀

El compa帽ero @C茅sarPalma dej贸 el siguiente comentario que me pareci贸 perfecto para entender un poco mejor鈥

En programaci贸n funcional, a esto se le llama hacer currying.
https://yeisondaza.com/currying-en-javascript-funciones-con-superpoderes

Agregar la imagen del pokemon:

export const addImageToPokemons = (store) => (next) => async (action) => {
    let pokemons = action.action.payload

    for (let i = 0; i < pokemons.length; i++) {
        const element = pokemons[i];
        let data = await getImagePokemon(element.name)
        let image = data.data.sprites.front_default

        element.image = image
    }

    next(action)
}

驴Esto esta bien implementado? Porque no necesito pasar la copia del estado 馃槙

Me esta gustando mucho este curso. La profesora se deja entender muy bien.

Hice un middleware que elimina un pokemon random de todos los que est谩n disponibles, deje console.log para que puedan ver cu谩l fue el seleccionado y como quedan los pokemons sin ese, aqui esta el middleware ==>

export const removeAnyPokemon = (_store) => (next) => (action) => {
    if (action.action.payload.length === 0) {
        return next(action);
    };

    const numberIdToDelete = Math.floor(Math.random() * action.action.payload.length);
    const pokemonToEliminate = action.action.payload[numberIdToDelete];

    console.log('Selected Pokemon Number and this Pokemon', numberIdToDelete, pokemonToEliminate);
    console.log('Array and its length before removing', action.action.payload, action.action.payload.length);
    
    action.action.payload.splice(numberIdToDelete, 1);
    
    console.log('Array after deletion and its length',action.action.payload, action.action.payload.length);
    
    next(action);
};

Con Redux Toolkit es 1000 veces m谩s sencillo implementar todos estas funciones. Entiendo que es bueno conocer la forma vieja de hacerlo, pero la explicaci贸n est谩 un poco mareada, es muy f谩cil perderse.

Este fue mi middleware

import { Middleware, Dispatch, Action } from 'redux';

const logger: Middleware = ({ getState }: any) => (next: Dispatch) => (action: Action) => {
  console.log('will dispatch', action);
  const returnValue = next(action);
  console.log('state after dispatch', getState());
  return returnValue;
};

const modifyName: Middleware = ({ getState }: any) => (next: Dispatch) => (action: {type:string,payload:any}) => {
    const payload = action.payload;
    payload.forEach((element: {name:string,url:string}) => {
        element.name = `Name: ${element.name}`
    });
    const returnValue = next(action);
    return returnValue;
};

const middleware = {logger,modifyName};
export default middleware;

Yo utilic茅 un Middleware para poner la primera letra de cada nombre en may煤scula.

export const upperCaseFirstLetterName = (store) =>(next) => (actionInfo) => {
    
    const pokemonsUp = actionInfo.payload.map(pokemon=>{
        
        const upperPok = pokemon.name.charAt(0).toUpperCase() + pokemon.name.slice(1)
        return {name: upperPok}
    })

    
    const updatedPayload = {
        ...actionInfo,
        payload: pokemonsUp
    }
    next(updatedPayload)
}

Currying es una t茅cnica de programaci贸n funcional que permite transformar una funci贸n que toma m煤ltiples argumentos en una secuencia de funciones que toman un solo argumento cada una.

El objetivo de currying es hacer que las funciones sean m谩s reutilizables y componibles, permitiendo a los desarrolladores crear funciones m谩s espec铆ficas a partir de funciones m谩s generales.

Mi middleware personalizado para agregarle una propiedad adicional 鈥渋sActive鈥 a cada pokemon:

export const addActivationProp = (store) => (next) => actionInfo => {
    const newPayload = actionInfo.action.payload.map(pokemon => pokemon.isActive = true);
    const newActionInfo = { ...actionInfo, payload: newPayload};
    next(newActionInfo);
}

El middeware que cree fue pokemonsWithId que agrega el id a los pokemons.

import types from '../actions/types';

const pokemonsWithId = (store) => (next) => (actionInfo) => {
  if (actionInfo.action.type === types.setPokemons) {
    const pokemons = actionInfo.action.payload;
    const pokemonsWithId = pokemons.map((pokemon, i) => ({ ...pokemon, id: i + 1 }));
    
    const updatedAction = {
      ...actionInfo,
      action: { ...actionInfo.action, payload: pokemonsWithId },
    };
    next(updatedAction);
  } else {
    next(actionInfo);
  }
};

export default pokemonsWithId;

Para usar los devtools y el middleware lo hice de la siguiente manera, use un paquete

npm install --save-dev redux-devtools-extension

import { composeWithDevTools } from "redux-devtools-extension";

const middlewareEnhancer = applyMiddleware(logger);

const store = createStore(
  pokemonsReducer,
  composeWithDevTools(middlewareEnhancer)
);

funciona perfecto por si alguno tiene un error y est谩 usando TypeScript