No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Manejo de Action Types y Action Creators en React Reducers

15/19
Recursos

Aportes 44

Preguntas 3

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Jah, el profe no me gano, puse pausa al video y termine primero !

Action Types: consiste en usar un objeto para almacenar las keys de nuestro reducer:

const actionTypes = {
   error: 'ERROR',
   confirm: 'CONFIRM',
}

Action Creators: consiste en declarar funciones que contienen nuestros dispatch:

const onError = () => dispatch({ type: actionTypes.error });
 
const onWrite = ({ target: { value } }) => {
    dispatch({ type: actionTypes.write, payload: value });
}

Min 11:26
No es que el lenguaje le ponga los parentesis, sino que le estamos dando una referencia de esa variable, cuando JS va a la variable se da cuenta que es una funcion, y la ejecuta. ✨

Le agregue la propiedad de disabled al input ya que me parecía algo raro que podamos seguir escribiendo cuando el loading esta en true.

<input
               disabled={state.loading}
               placeholder="Codigo de seguridad"
               value={state.value}
               onChange={onWrite}
/>

Así cuando loading sea true, disabled será true y viceversa.

actionTypes

  • Cuando llamamos a dispath debemos darle un valor a action.type.
  • Con el uso de actionTypes podremos evitar los errores de tipeo.
  • consiste en usar un objeto para almacenar las keys de nuestro reducer

Action creators:

  • Son funciones para actualizar el estado
  • Consiste en declarar funciones que contienen nuestros dispatch

Mi mamá ortografica estará fudiosa 🤣

Agregue algunos estilos básicos…
.

Ese momento donde agradeces tener GitHub Copilot y le ganas al profe xd, tal vez hice un poco de trampa jajaja

Usando actionTypes con switch/case:

import React, { useEffect, useReducer, Fragment } from 'react'

const SECURITY_CODE = 'paradigma'

const initialState = {
	value: '',
	loading: false,
	error: false,
	deleted: false,
	confirmed: false,
}

const actionTypes = {
	error: 'Error',
	confirm: 'Confirm',
	write: 'Write',
	check: 'Check',
	delete: 'Delete',
	reset: 'Reset',
}

const reducer = (state, action) => {
	switch (action.type) {
		case actionTypes.error :
			return {
				...state,
				error: true,
				loading: false,
			}
		case actionTypes.confirm :
			return {
				...state,
				loading: false,
				error: false,
				confirmed: true,
			}
		case actionTypes.write :
			return {
				...state,
				value: action.payload,
			}
		case actionTypes.check :
			return {
				...state,
				loading: true,
				error: false,
			}
		case actionTypes.delete :
			return {
				...state,
				deleted: true,
			}
		case actionTypes.reset :
			return {
				...state,
				value: '',
				confirmed: false,
				deleted: false,
			}
		default:
			return {
				...state,
			}
	}
}

export default function UseReducer() {
	const [ state, dispatch ] = useReducer(reducer, initialState)

	useEffect(
		() => {
			if (state.loading) {
				setTimeout(() => {
					if (state.value === SECURITY_CODE) {
						dispatch({ type: actionTypes.confirm })
					} else {
						dispatch({ type: actionTypes.error })
					}
				}, 1000)
			}
		},
		[ state.loading ]
	)

	if (!state.deleted && !state.confirmed) {
		return (
			<div>
				<h2>Eliminar UseReducer</h2>
				<p>Por favor, escriba el código de seguridad.</p>
				{state.loading ? 'Cargando...' : state.error ? 'Error :(' : null}
				<br />
				<input
					type='text'
					placeholder='código de seguridad'
					value={state.value}
					onChange={ev => dispatch({ type: actionTypes.write, payload: ev.target.value })}
				/>
				<button onClick={() => dispatch({ type: actionTypes.check })}>Comprobar</button>
			</div>
		)
	} else if (!state.deleted && state.confirmed) {
		return (
			<Fragment>
				<p>Pedimos confirmación. ¿Tas seguro?</p>
				<button onClick={() => dispatch({ type: actionTypes.delete })}>Si, eliminar</button>
				<button onClick={() => dispatch({ type: actionTypes.reset })}>No, me arrepentí</button>
			</Fragment>
		)
	} else {
		return (
			<Fragment>
				<p>Eliminado con éxito</p>
				<button onClick={() => dispatch({ type: actionTypes.reset })}>Regresar</button>
			</Fragment>
		)
	}
}

Me volvió a pasar lo mismo que con los otros cursos de este profesor, aunque considero que explica muy bien y sabe mucho;
te marea demasiado cuando va borrando y cambiando tanto el código. Tal vez está bueno que se explique de una como sería, o buscar otro método de explicar los conceptos. Realmente es bastante confusa esta manera de explicar.

con TypeScript podemos evitar los errores ortograficos, utilizando type o interfaces

type State = {
    error: boolean,
    loading: boolean,
    value: string,
    deleted: boolean,
    confirmed: boolean
}

type Action = {
    type: "CHECK" | "ERROR" | "CONFIRM" | "WRITE" | "DELETED" | "RESET",
    payload?: string
}

const reducerObject = <T,>(state: T, payload = "") => ({
    CONFIRM: {
        ...state,
        error: false,
        loading: false,
        confirmed: true
    },
    ERROR: {
        ...state,
        error: true,
        loading: false
    },
    CHECK: { 
        ...state,
        loading: true
    },
    WRITE: {
        ...state,
        value: payload
    },
    DELETED: {
        ...state,
        deleted: true
    },
    RESET: {
        ...state,
        confirmed: false,
        deleted: false,
        value: ""
    }
})

const reducer = (state: State, action: Action): State => {
    return reducerObject(state, action.payload)[action.type]
}

Creería que la parte de Action Types no sería necesaria si utilizamos Typescript para React. Ya que explícitamente puedo declararle los tipos que puede soportar la key “type” de la siguiente forma:

type Action ={
type: ‘WRITE’ | ‘CONFIRM’ | ‘ERROR’ | ‘DELETE’ | ‘CHECK’ | ‘RESET’,
payload?: string,
}

Entonces si me llego a equivocar, TS automáticamente lo detecta y me arroja el error.

Es en estos casos donde prefiero typescript

Yo pase el argumento de onWrite de la siguiente manera :

        <input 
          placeholder="Código de Seguridad" 
          value={state.value} 
          onChange={e => {
            onWrite(e.target.value)
        }}/>

y en el action creator

  const onWrite = (newValue) => {
    setState({
      ...state,
      value: newValue
    })
  } 

Este es el resultado final de el proyecto trabajado en este curso

No se hasta que punto conviene hacer el codigo tan declarativo… lo cuestiono mucho

por que se complica tanto ??? me parece innesesario e.e

Sintaxis para asignar el valor de una variable como llave de un objeto:

const username = "juan"

const obj = {
	[username]: "hernandez"
}

console.log(obj.juan) //hernandez

Link

Pienso que cada vez escribimos mucho más código...

Action creators y actionTypes

.
Cuando utilizamos un dispatch es necesario enviar un nombre a la propiedad type, el único problema que podría acontecer en ese punto sería enviarle un nombre incorrecto. Esto implica que el estado no va a cambiar y entraríamos en caso de estado por defecto si utilizamos un switch, dentro del else si usamos un if, el mismo estado que recibimos si usamos un objeto.
.
Para evitar esto utilizaremos los actionTypes que básicamente consiste en un objeto que tiene como propiedades a estos textos escritos como key y value, haciendo que solo tengamos que escribirlo una vez. Por lo cual si nos equivocáramos a escribirlo solo lo tendríamos que corregir en un solo lugar.
.

const actionTypes = {
  confirm: 'CONFIRM',
  delete: 'DELETE',
  error: 'ERROR',
  write: 'WRITE',
  reset: 'RESET',
};

.
El valor clave de este objeto puede escribirse incluso en mayúscula, y por medio de actionTypes.confirm por ejemplo puede accederse a la propiedad correspondiente y se puede utilizar sin problemas en los llamados a dispatch.
.

dispatch({ type: actionType.confirm })

.
Exactamente lo mismo se puede hacer en nuestro reducerObject. En lugar de escribir el nombre de la clave por medio de un string, se puede escribir por medio de corchetes y adentro el actionType.confirm por ejemplo.
.

const reducerObject = (state, payload) => ({
  [actionTypes.confirm]: {
    ...state,
    error: false,
    loading: false,
    confirmed: true,
  },
  ...
}

.
De esta manera vamos a aplicar estos cambios para todas las claves de acciones de nuestro reducerObject y llamados a dispatch donde utilizábamos a strings en lugar de los actionTypes.
.
Posteriormente, al igual que pudimos abstraer la lógica en el componente useState para actualizar el estado de una manera declarativa por medio de funciones que llamaban a setState; también podemos hacer lo mismo cuando utilizamos useReducer, pero en este caso ya no se llaman funciones actualizadoras del estado sino que action creators.
.
La única diferencia es que ahora el código que tienen por dentro estas funciones ya no son imperativas, sino que declarativas por medio del dispatch.
.

const onConfirm = () => {
	dispatch({ type: actionTypes.confirm });
};

.
Incluso puede volverse más legible si utilizamos un return implicito.
.

const onConfirm = () => dispatch({ type: actionTypes.confirm });
const onError = () => dispatch({ type: actionTypes.error });
const onCheck = () => dispatch({ type: actionTypes.check });
const onDelete = () => dispatch({ type: actionTypes.delete });
const onReset = () => dispatch({ type: actionTypes.reset });
  
const onWrite = ({ target: { value } }) => {
  dispatch({ type: actionTypes.write, payload: value });
}

.
En el caso del onWrite por la forma en la que lo vamos a llamar en la interfaz onChange={onWrite} veremos que podemos destructurar el evento que recibimos en su propiedad target, y a su vez destructurarlo a su vez en su propiedad value para obtener un código aún más legible.
.


const onWrite = (event) => {
  dispatch({ type: actionTypes.write, payload: event.target.value });
}

const onWrite = ({ target }) => {
  dispatch({ type: actionTypes.write, payload: target.value });
}
// Forma más legible
const onWrite = ({ target: { value } }) => {
  dispatch({ type: actionTypes.write, payload: value });
}

.
Finalmente, donde teníamos actuando a nuestros dispatch vamos a utilizar nuestros action creators.
.

...
function UseReducer({ name }) {
  const [state, dispatch] = React.useReducer(reducer, initialState);

  const onConfirm = () => dispatch({ type: actionTypes.confirm });
  const onError = () => dispatch({ type: actionTypes.error });
  const onCheck = () => dispatch({ type: actionTypes.check });
  const onDelete = () => dispatch({ type: actionTypes.delete });
  const onReset = () => dispatch({ type: actionTypes.reset });
  
  const onWrite = ({ target: { value } }) => {
    dispatch({ type: actionTypes.write, payload: value });
  }

  React.useEffect(() => {

    if (!!state.loading) {
      setTimeout(() => {
  
        if (state.value === SECURITY_CODE) {
          onConfirm();
        } else {
          onError();
        }
        
      }, 3000);
    }
    
  }, [state.loading]);
  
  if (!state.deleted && !state.confirmed) {
    return (
      <div>
        <h2>Eliminar {name}</h2>
        
        <p>Por favor, escribe el código de seguridad.</p>
  
        {(state.error && !state.loading) && (
          <p>Error: el código es incorrecto</p>
        )}
        {state.loading && (
          <p>Cargando...</p>
        )}
  
        <input
          placeholder="Código de seguridad"
          value={state.value}
          onChange={onWrite}
        />
        <button onClick={onCheck}>
          Comprobar
        </button>
      </div>
    );
  } else if (!!state.confirmed && !state.deleted) {
    return (
      <React.Fragment>
        <p>Pedimos confirmación. ¿Tas segurx?</p>

        <button onClick={onDelete}>
          Sí, eliminar
        </button>
        <button onClick={onReset}>
          Nop, me arrepentí
        </button>
      </React.Fragment>
    );
  } else {
    return (
      <React.Fragment>
        <p>Eliminado con éxito</p>

        <button onClick={onReset}>
          Resetear, volver atrás
        </button>
      </React.Fragment>
    );
  }
}

...

.
Como podemos dentro de los eventos de nuestra interfaz como el onClick o el onChange ya no estamos utilizando una función flecha que por dentro llama a otra función, sino que escribimos directamente a la función correspondiente sin parentesis.
.

<button
	onClick={() => {
		onCheck();
	}}
>
	Comprobar
</button>

<button onClick={() => onCheck()}>
          Comprobar
</button>
// Forma más legible
<button onClick={onCheck}>
          Comprobar
</button>

.
Estos actionTypes y action creators nos ayudan a mejorar la legibilidad de nuestro código. Por supuesto, un código imperativo no es mejor que un código declarativo, y viceversa. Simplemente pueden ayudarnos a mejorar la legibilidad de nuestro código o simplemente enfocarnos a obtener resultados lo más pronto posible.

Lo que mas me gusto de esta clase fue la forma en la que utilizamos el actionTypes que si uno quisiera con typescript podria usarlo como un enum y listo ya no mas switches

Super útil, gracias!

Me recuerda a los enums en Kotlin

Si bien en el onChange se resumia en cuanto a la legibilidad aconsejo que se haga de siguiente, en resumen quedarnos con la anterior version, esto ya que cuando se intenta dar soporte a proyectos grandes estos necesitan tal cual ser ‘faciles de leer’

  • Por cierto si hablamos en terminos de la complejidad que pueda tener la redundancia, se podria decir que simplemente llega a ser
          onChange={(event) => onWrite(event.target.value)} 

Complexity(lineal), si me equivoco me corrigen por favor:

  const dun = (event.target.value) => (value) => {
    dispatch({ type: actionTypes.write, payload: value})
  };

Fuente: https://www.cs.us.es/~jalonso/cursos/i1m-19/temas/tema-28.html

Usar types en typescript o interface para el tipado es otra alternativa para este caso.

Action Creators

Incluso podemos crear un archivo propio para los actionTypes:

export const ACTION_TYPES = {
  CHECK: 'CHECK',
  CONFIRM: 'CONFIRM',
  DELETE: 'DELETE',
  ERROR: 'ERROR',
  RESET: 'RESET',
  WRITE: 'WRITE',
}

Ya después lo mandamos a llamar en el archivo que lo necesitemos:

import { useReducer, useEffect, useCallback } from 'react'
import { ACTION_TYPES } from './actionTypes'
import './UseState.css'

const SECURITY_CODE = 'techzone'

function UseReducer({name}) {
  const [state, dispatch] = useReducer(reducer, initialState)

  const onCheck = () => dispatch({ type: ACTION_TYPES.CHECK })

  const onConfirm = () => dispatch({ type: ACTION_TYPES.CONFIRM })

  const onDelete = () => dispatch({ type: ACTION_TYPES.DELETE })

  const onError = () => dispatch({ type: ACTION_TYPES.ERROR })

  const onReset = () => dispatch({ type: ACTION_TYPES.RESET })

  const onWrite = ({target: { value }}) => dispatch({ type: ACTION_TYPES.WRITE, payload: value })

  const changeState = useCallback(() => {
    if (state.loading) {
      setTimeout(() => {
        state.value === SECURITY_CODE ? onConfirm() : onError()
      }, 2000)
    }
  }, [state])

  useEffect(() => {
    changeState()
  }, [changeState])

  if (!state.deleted && !state.confirmed) {
    return (
      <div>
        <h2>Eliminar {name}</h2>
        <p>Por favor escribe el código de seguridad</p>

        { state.error && (<p>Error: el código es incorrecto</p>) }

        { state.loading && (<p>Loading...</p>) }

        <input
          type="text"
          placeholder="Código de seguridad"
          value={state.value}
          onChange={onWrite}
        />
        <button onClick={onCheck}
        >
          Comprobar
        </button>
      </div>
    )
  } else if (state.confirmed && !state.deleted) {
    return (
      <>
        <p>
          Advertencia ⚠️, ¿Estás seguro de querer eliminar esto?
          <span className='red'>
            Es irrecuperable
          </span>
        </p>
        <button onClick={onDelete}>
          Sí, eliminar
        </button>

        <button onClick={onReset}>
          No, me arrepentí
        </button>
      </>
    )
  } else {
    return (
      <>
        <p>Eliminado con éxito</p>
        <button onClick={onReset}>
          Resetear
        </button>
      </>
    )
  }
}

const initialState = {
  confirmed: false,
  deleted: false,
  error: false,
  loading: false,
  value: '',
}

const reducerObject = (state, payload) => ({
  [ACTION_TYPES.WRITE]: {
    ...state,
    value: payload
  },

  [ACTION_TYPES.CONFIRM]: {
    ...state,
    error: false,
    confirmed: true,
    loading: false
  },

  [ACTION_TYPES.ERROR]: {
    ...state,
    error: true,
    loading: false
  },

  [ACTION_TYPES.CHECK]: {
    ...state,
    loading: true,
  },

  [ACTION_TYPES.DELETE]: {
    ...state,
    deleted: true
  },

  [ACTION_TYPES.RESET]: {
    ...state,
    confirmed: false,
    deleted: false,
    value: ''
  }
})

const reducer = (state, action) => {
  if (reducerObject(state)[action.type]) {
    return reducerObject(state, action.payload)[action.type]
  } else {
    return state
  }
}

export { UseReducer }

Mi Practica

```jsx
importReactfrom "react";

const SECURITY_CODE = "paradigma";

function UseReducer({name}) {
    const [state, dispatch] =React.useReducer(reducer, initialState);
    const onConfirm = () => {
        dispatch({type: actionTypes.confirm});
    }
    const onError = () => {
        dispatch({type: actionTypes.error});
    }
    const onWrite = (eventValue) => {
        dispatch({type: actionTypes.write, payload:eventValue});
    }
    const onCheck = () => {
        dispatch({type: actionTypes.check});
    }
    const onDelete = () => {
        dispatch({type: actionTypes.delete});
    }
    const onReset = () => {
        dispatch({type: actionTypes.reset});
    }
React.useEffect(() => {

        if (!!state.loading) {
            setTimeout(() => {
                if (state.value === SECURITY_CODE) {
                    onConfirm()
                } else {
                    onError()
                }

            }, 3000);
        }
    }, [state.loading]);
    if (!state.deleted && !state.confirmed) {
        return (
            <React.Fragment>
                <h2>Eliminar{name}</h2>
                <p>Por favor, escribe el código de seguridad</p>
                {(!state.loading && state.error) && (
                    <p>El Código es incorrecto</p>
                )}
                {state.loading && (
                    <p>Cargando...</p>
                )}
                <input
                    value={state.value}
                    onChange={(event) => {
                        onWrite(event.target.value)
                    }}

                    placeholder="Código de Seguridad"
                />
                <button
                    onClick={onCheck}
                >Comprobar
</button>
            </React.Fragment>
        );
    } else if (!!state.confirmed && !state.deleted) {
        return (
            <React.Fragment>
                <h2>Eliminar{name}</h2>
                <p>¿Seguro que quieres eliminar{name}?</p>
                <button type="button" onClick={onDelete}>Si, eliminar
</button>
                <button type="button" onClick={onReset}>No, cancelar
</button>
            </React.Fragment>
        );
    } else {
        return (
            <React.Fragment>
                <h2>¡{name}eliminado!</h2>
                <button type="button" onClick={onReset}>Recuperar{name}</button>
            </React.Fragment>
        );
    }
}

const initialState = {
    value: "",
    error: false,
    loading: false,
    deleted: false,
    confirmed: false
};
const actionTypes = {
    confirm: 'CONFIRM',
    error: 'ERROR',
    write: 'WRITE',
    check: 'CHECK',
    delete: 'DELETE',
    reset: 'RESET',
}
const reducerObject = (state,payload= false) => ({
    [actionTypes.confirm]: {
        ...state,
        error: false,
        loading: false,
        confirmed: true
    },
    [actionTypes.error]: {
        ...state,
        error: true,
        loading: false
    },
    [actionTypes.write]: {
        ...state,
        value:payload
},
    [actionTypes.check]: {
        ...state,
        loading: true
    },
    [actionTypes.delete]: {
        ...state,
        deleted: true
    },
    [actionTypes.reset]: {
        ...state,
        confirmed: false,
        deleted: false,
        value: ''
    },
});
const reducer = (state,action) => {
    if (reducerObject(state)[action.type]) {
        return reducerObject(state,action.payload)[action.type]
    } else {
        returnstate;
    }
}

export {UseReducer};

Un gran poder, conlleva una gran responsabilidad.

ayuda! tenia que haber parado hace 5 clases, esto está muy interesante.

No sabia ese truco con la restructuración en el onchange ! que cool
Iba excelente hasta la clase anterior, pero con tanto reemplazo del código ya escrito se reventó la aplicación, y ni modo
wooow quedo súper limpio el código!!!
Admirar mi creación jaja ```js import { useEffect, useReducer } from "react"; const KEY_VALUE = "usereducer"; export default function UseReducer({ name }) { const InitialState = { value: "", error: false, loading: false, deleted: false, confirmed: false, }; //Reducer const actionTypes = { error: "ERROR", write: "WRITE", check: "CHECK", confirm: "CONFIRM", delete: "DELETE", reset: "RESET", }; const reducerObjt = (state, payload) => ({ [actionTypes.error]: { ...state, error: true, loading: false, }, [actionTypes.write]: { ...state, value: payload, }, [actionTypes.check]: { ...state, loading: true, }, [actionTypes.confirm]: { ...state, error: false, loading: false, confirmed: true, }, [actionTypes.delete]: { ...state, deleted: true, }, [actionTypes.reset]: { ...state, deleted: false, confirmed: false, value: "", }, }); const reducer = (state, action) => { const type = reducerObjt(state, action.payload)[action.type]; if (type) return type; return state; }; //Reducer State const [state, dispatch] = useReducer(reducer, InitialState); //Action creators const onConfirm = () => dispatch({ type: actionTypes.confirm }); const onError = () => dispatch({ type: actionTypes.error }); const onWrite = (newValue) => dispatch({ type: actionTypes.write, payload: newValue }); const onCheck = () => dispatch({ type: actionTypes.check }); const onDelete = () => dispatch({ type: actionTypes.delete }); const onReset = () => dispatch({ type: actionTypes.reset }); useEffect(() => { if (!!state.loading) { setTimeout(() => { if (state.value === KEY_VALUE) { onConfirm(); } else { onError(); } }, 2000); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [state.loading]); //Components const WriteCodigo = ( <>

Eliminar {name}

{state.loading &&

Cargando ...

} {!state.loading &&

Por favor, escribe el código de seguridad.

} {state.error && !state.loading && (

El código es es incorrecto

)} <input placeholder="Código de seguridad" value={state.value} onChange={(e) => onWrite(e.target.value)} /> <button type="button" onClick={() => onCheck()}> Comprobar </button> ); const Confirmed = ( <>

Pedimos confirmación, ¿Estas Seguro?

<button type="button" onClick={() => onDelete()}> Sí 😬, Eliminalo ❌ </button> <button type="button" onClick={() => onReset()}> Ummm 🤔, mejor ya no 😅 </button> ); const DeletedSucces = ( <>

Eliminado con Exito

<button type="button" onClick={() => onReset()}> Resetear 🔂, Volcer atrás 👈 </button> ); return (
{!state.deleted && !state.confirmed && WriteCodigo} {!!state.confirmed && !state.deleted && Confirmed} {state.deleted && DeletedSucces}
); } ```
Soy de los que tipean mal las palabras <3
````js le falto el onCheck en el objeto actionTypes, mi código declarativo con reducers: import { useEffect, useReducer } from "react"; const SECURITY_CODE = "paradigma"; function UseReducer({ name }) { const initialState = { value: "", error: false, loading: false, deleted: false, confirmed: false, }; const actionTypes = { error: "ERROR", confirm: "CONFIRM", check: "CHECK", write: "WRITE", delete: "DELETE", reset: "RESET", }; const reducer = (state, action) => { switch (action.type) { case actionTypes.error: return { ...state, error: true, loading: false, }; case actionTypes.confirm: return { ...state, loading: false, confirmed: true, }; case actionTypes.check: return { ...state, loading: true, error: false, }; case actionTypes.write: return { ...state, value: action.payload, }; case actionTypes.delete: return { ...state, deleted: true, }; case actionTypes.reset: return { ...state, deleted: false, confirmed: false, }; default: return state; } }; const [state, dispatch] = useReducer(reducer, initialState); useEffect(() => { console.log("iniciando efecto"); if (state.loading) { console.log("Haciendo validación en efecto"); setTimeout(() => { if (state.value !== SECURITY_CODE) { onError(); } else { onConfirm(); } }, 3000); } }, [state.loading]); const onError = () => { dispatch({ type: actionTypes.error }); }; const onConfirm = () => { dispatch({ type: actionTypes.confirm }); }; const onCheck = () => { dispatch({ type: actionTypes.check }); }; const onWrite = (event) => { dispatch({ type: actionTypes.write, payload: event.target.value }); }; const onDelete = () => { dispatch({ type: actionTypes.delete }); }; const onReset = () => { dispatch({ type: actionTypes.reset }); }; if (!state.deleted && !state.confirmed) { return (

{name}

Por favor, escribe el código de seguridad.

{state.error &&

Error codigo incorrecto

} {state.loading &&

cargando...

} <input type="text" placeholder="escribe el godigo de seguridad" onChange={onWrite} /> <button onClick={onCheck}>Comprobar</button>
); } else if (!state.deleted && state.confirmed) { return ( <>

Seguro que quiere eliminar?

<button onClick={onDelete}>si, eliminar</button> <button onClick={onReset}>no, quiero cancelar</button> ); } else { return ( <>

Eliminado con éxito

<button onClick={onReset}>resetear, volver atrás</button> ); } } export { UseReducer }; ```le falto el onCheck en el objeto actionTypes, mi código declarativo con reducers: import { useEffect, useReducer } from "react"; const SECURITY\_CODE = "paradigma"; function UseReducer({ name }) { const initialState = { value: "", error: false, loading: false, deleted: false, confirmed: false, }; const actionTypes = { error: "ERROR", confirm: "CONFIRM", check: "CHECK", write: "WRITE", delete: "DELETE", reset: "RESET", }; const reducer = (state, action) => { switch (action.type) { case actionTypes.error: return { ...state, error: true, loading: false, }; case actionTypes.confirm: return { ...state, loading: false, confirmed: true, }; case actionTypes.check: return { ...state, loading: true, error: false, }; case actionTypes.write: return { ...state, value: action.payload, }; case actionTypes.delete: return { ...state, deleted: true, }; case actionTypes.reset: return { ...state, deleted: false, confirmed: false, }; default: return state; } }; const \[state, dispatch] = useReducer(reducer, initialState); useEffect(() => { console.log("iniciando efecto"); if (state.loading) { console.log("Haciendo validación en efecto"); setTimeout(() => { if (state.value !== SECURITY\_CODE) { onError(); } else { onConfirm(); } }, 3000); } }, \[state.loading]); const onError = () => { dispatch({ type: actionTypes.error }); }; const onConfirm = () => { dispatch({ type: actionTypes.confirm }); }; const onCheck = () => { dispatch({ type: actionTypes.check }); }; const onWrite = (event) => { dispatch({ type: actionTypes.write, payload: event.target.value }); }; const onDelete = () => { dispatch({ type: actionTypes.delete }); }; const onReset = () => { dispatch({ type: actionTypes.reset }); }; if (!state.deleted && !state.confirmed) { return ( \
\

{name}\

\

Por favor, escribe el código de seguridad.\

{state.error && \

Error codigo incorrecto\

} {state.loading && \

cargando... \

} \<input type="text" placeholder="escribe el godigo de seguridad" onChange={onWrite} /> \<button onClick={onCheck}>Comprobar\</button> \
); } else if (!state.deleted && state.confirmed) { return ( <> \

Seguro que quiere eliminar?\

\<button onClick={onDelete}>si, eliminar\</button> \<button onClick={onReset}>no, quiero cancelar\</button> \ ); } else { return ( <> \

Eliminado con éxito\

\<button onClick={onReset}>resetear, volver atrás\</button> \ ); } } export { UseReducer }; ````
import { useEffect, useReducer } from "react";     const SECURITY\_CODE = "paradigma";     function UseReducer({ name }) {    const initialState = {    value: "",    error: false,    loading: false,    deleted: false,    confirmed: false,    };     const actionTypes = {    error: "ERROR",    confirm: "CONFIRM",    check: "CHECK",    write: "WRITE",    delete: "DELETE",    reset: "RESET",    };     const reducer = (state, action) => {      switch (action.type) {        case actionTypes.error:          return {            ...state,            error: true,            loading: false,          };        case actionTypes.confirm:          return {            ...state,            loading: false,            confirmed: true,          };        case actionTypes.check:          return {            ...state,            loading: true,            error: false,          };        case actionTypes.write:          return {            ...state,            value: action.payload,          };        case actionTypes.delete:          return {            ...state,            deleted: true,          };        case actionTypes.reset:          return {            ...state,            deleted: false,            confirmed: false,          };        default:          return state;      }    };     const \[state, dispatch] = useReducer(reducer, initialState);     useEffect(() => {      console.log("iniciando efecto");       if (state.loading) {        console.log("Haciendo validación en efecto");        setTimeout(() => {          if (state.value !== SECURITY\_CODE) {            onError();          } else {            onConfirm();          }        }, 3000);      }    }, \[state.loading]);     const onError = () => {      dispatch({ type: actionTypes.error });    };     const onConfirm = () => {      dispatch({ type: actionTypes.confirm });    };     const onCheck = () => {      dispatch({ type: actionTypes.check });    };     const onWrite = (event) => {      dispatch({ type: actionTypes.write, payload: event.target.value });    };     const onDelete = () => {      dispatch({ type: actionTypes.delete });    };     const onReset = () => {      dispatch({ type: actionTypes.reset });    };     if (!state.deleted && !state.confirmed) {      return (        \
          \

{name}\

          \

Por favor, escribe el código de seguridad.\

          {state.error && \

Error codigo incorrecto\

}          {state.loading && \

cargando... \

}          \<input            type="text"            placeholder="escribe el godigo de seguridad"            onChange={onWrite}          />          \<button onClick={onCheck}>Comprobar\</button>        \
      );    } else if (!state.deleted && state.confirmed) {      return (        <>          \

Seguro que quiere eliminar?\

          \<button onClick={onDelete}>si, eliminar\</button>          \<button onClick={onReset}>no, quiero cancelar\</button>        \      );    } else {      return (        <>          \

Eliminado con éxito\

          \<button onClick={onReset}>resetear, volver atrás\</button>        \      );    }    }     export { UseReducer };
le falto el onCheck en el objeto actionTypes, mi código declarativo con reducers:     import { useEffect, useReducer } from "react";     const SECURITY\_CODE = "paradigma";     function UseReducer({ name }) {    const initialState = {    value: "",    error: false,    loading: false,    deleted: false,    confirmed: false,    };     const actionTypes = {    error: "ERROR",    confirm: "CONFIRM",    check: "CHECK",    write: "WRITE",    delete: "DELETE",    reset: "RESET",    };     const reducer = (state, action) => {      switch (action.type) {        case actionTypes.error:          return {            ...state,            error: true,            loading: false,          };        case actionTypes.confirm:          return {            ...state,            loading: false,            confirmed: true,          };        case actionTypes.check:          return {            ...state,            loading: true,            error: false,          };        case actionTypes.write:          return {            ...state,            value: action.payload,          };        case actionTypes.delete:          return {            ...state,            deleted: true,          };        case actionTypes.reset:          return {            ...state,            deleted: false,            confirmed: false,          };        default:          return state;      }    };     const \[state, dispatch] = useReducer(reducer, initialState);     useEffect(() => {      console.log("iniciando efecto");       if (state.loading) {        console.log("Haciendo validación en efecto");        setTimeout(() => {          if (state.value !== SECURITY\_CODE) {            onError();          } else {            onConfirm();          }        }, 3000);      }    }, \[state.loading]);     const onError = () => {      dispatch({ type: actionTypes.error });    };     const onConfirm = () => {      dispatch({ type: actionTypes.confirm });    };     const onCheck = () => {      dispatch({ type: actionTypes.check });    };     const onWrite = (event) => {      dispatch({ type: actionTypes.write, payload: event.target.value });    };     const onDelete = () => {      dispatch({ type: actionTypes.delete });    };     const onReset = () => {      dispatch({ type: actionTypes.reset });    };     if (!state.deleted && !state.confirmed) {      return (        \
          \

{name}\

          \

Por favor, escribe el código de seguridad.\

          {state.error && \

Error codigo incorrecto\

}          {state.loading && \

cargando... \

}          \<input            type="text"            placeholder="escribe el godigo de seguridad"            onChange={onWrite}          />          \<button onClick={onCheck}>Comprobar\</button>        \
      );    } else if (!state.deleted && state.confirmed) {      return (        <>          \

Seguro que quiere eliminar?\

          \<button onClick={onDelete}>si, eliminar\</button>          \<button onClick={onReset}>no, quiero cancelar\</button>        \      );    } else {      return (        <>          \

Eliminado con éxito\

          \<button onClick={onReset}>resetear, volver atrás\</button>        \      );    }    }     export { UseReducer };
Para esto tambien se pueden utilizar los enums de typescript. Aqui un ejemplo de unos contadores implementando estos enums. ```js export type CountersState = { counterA: number; counterB: number; } export type Action = { type: ActionTypes; } export enum ActionTypes { INCREMENT_COUNTER_A = 'INCREMENT_COUNTER_A', DECREMENT_COUNTER_A = 'DECREMENT_COUNTER_A', INCREMENT_COUNTER_B = 'INCREMENT_COUNTER_B', DECREMENT_COUNTER_B = 'DECREMENT_COUNTER_B', RESET_COUNTER_A = 'RESET_COUNTER_A', RESET_COUNTER_B = 'RESET_COUNTER_B', } export type ReducerObject = { [ActionTypes.INCREMENT_COUNTER_A]: CountersState, [ActionTypes.DECREMENT_COUNTER_A]: CountersState, [ActionTypes.INCREMENT_COUNTER_B]: CountersState, [ActionTypes.DECREMENT_COUNTER_B]: CountersState, [ActionTypes.RESET_COUNTER_A]: CountersState, [ActionTypes.RESET_COUNTER_B]: CountersState, } const initialState: CountersState = { counterA: 0, counterB: 0, } const reducerObject = (state: CountersState): ReducerObject => ( { [ActionTypes.INCREMENT_COUNTER_A]: {...state, counterA: state.counterA + 1}, [ActionTypes.DECREMENT_COUNTER_A]: {...state, counterA: state.counterA - 1}, [ActionTypes.INCREMENT_COUNTER_B]: {...state, counterB: state.counterB + 1}, [ActionTypes.DECREMENT_COUNTER_B]: {...state, counterB: state.counterB - 1}, [ActionTypes.RESET_COUNTER_A]: {...state, counterA: 0}, [ActionTypes.RESET_COUNTER_B]: {...state, counterB: 0}, } ) const reducer = (state: CountersState, action: Action): CountersState => { if(reducerObject(state)[action.type]) return reducerObject(state)[action.type] else return state } function UseReducer() { const [state, dispatch] = useReducer(reducer, initialState); return ( <>

UseState

UseReducer

Counter A

{state.counterA}

<button onClick={() => dispatch({type: ActionTypes.DECREMENT_COUNTER_A})}>-</button> <button onClick={() => dispatch({type: ActionTypes.RESET_COUNTER_A})}>Reset</button> <button onClick={() => dispatch({type: ActionTypes.INCREMENT_COUNTER_A})}>+</button>

Counter B

{state.counterB}

<button onClick={() => dispatch({type: ActionTypes.DECREMENT_COUNTER_B})}>-</button> <button onClick={() => dispatch({type: ActionTypes.RESET_COUNTER_B})}>Reset</button> <button onClick={() => dispatch({type: ActionTypes.INCREMENT_COUNTER_B})}>+</button>

) } export default UseReducer ```

no me ganaste, porque yo te puse en pausa mientras lo hice. Técnicamente detuve tu tiempo. así que a pesar de usar ‘cámara rápida’ yo claramente salí ganador

Código de la clase en TypeScript:
Debo decir que en este caso TS nos ofrece unas interesantes formas de trabajar esto:

import { ChangeEvent, FC, useEffect, useReducer } from "react"

type Props = {
    name: string
}

type State = {
    value: string,
    error: boolean,
    loading: boolean,
    deleted: boolean,
    confirmed: boolean,
}

enum ActionTypes {
    CHECK = 'CHECK',
    ERROR = 'ERROR',
    CONFIRM = 'CONFIRM',
    DELETE = 'DELETE',
    RESET = 'RESET',
    WRITE = 'WRITE',
}

interface Action {
    type: ActionTypes,
    payload?: any
}

const initialState:State = {
    value: '',
    error: false,
    loading: false,
    confirmed: false,
    deleted: false,
};


const SECURITY_CODE = 'paradigma';


const UseReducer:FC<Props> = ({ name }) => {
    const [state, dispatch] = useReducer(reducer, initialState);

    const onConfirmed = () => {dispatch({ type: ActionTypes.CONFIRM })};
    const onError = ()=>{dispatch({ type: ActionTypes.ERROR })};
    const onWrite = ({ target : { value }}:ChangeEvent<HTMLInputElement>)=>{dispatch({ type: ActionTypes.WRITE , payload: value})};
    const onCheck = ()=>{dispatch({ type: ActionTypes.CHECK })};
    const onDelete = ()=>{dispatch({ type: ActionTypes.DELETE })};
    const onReset = ()=>{dispatch({ type: ActionTypes.RESET })};

    console.log(state);

    useEffect(()=>{
        console.log('Empezando el efecto');
        if(state.loading){
            console.log(state.  loading);
            setTimeout(()=>{
                console.log("Haciendo la validación");
                if(state.value === SECURITY_CODE){
                    onConfirmed();
                } else {
                    onError();
                }
                console.log("Terminando la validación");
            },3000)
        }
        console.log('Terminando el efecto');
    },[state.loading]);


    if(!state.deleted && !state.confirmed){
        return(
            <div>
                <h2>Eliminar { name }</h2>
                <p>Por favor, escribe el código de seguridad para comprobar que quieres eliminar</p>
    
                {state.error && !state.loading && (
                    <p>El código es incorrecto</p>
                )}
    
                {state.loading && (
                    <p>Cargando ...</p>
                )}
    
                <input 
                    type="text" 
                    placeholder="Código de seguridad" 
                    value={state.value}
                    onChange={onWrite}
                />
    
                <button
                    onClick={()=>{
                        onCheck();
                    }}
                >Comprobar</button>
            </div>
    )} else if(!state.deleted && state.confirmed) {
        return(
            <>
                <p>¿Seguro que quieres eliminar { name }</p>
                <button
                    onClick={onDelete}
                >Si, eliminar</button>
                <button
                    onClick={onReset}
                >No, volver</button>
            </>
        )
    } else {
        return(
            <>
                <p>Estado de eliminación</p>
                <button
                    onClick={onReset}
                >Resetear, volver atrás</button>
            </>
        )
    }

}

const reducerObject = (state: State, action:Action): {[k in ActionTypes]: State} => ({
    CONFIRM:{
        ...state,
        loading: false,
        error: false,
        confirmed: true,
    },
    ERROR: {
        ...state,
        loading: false,
        error: true,
    },
    CHECK: {
        ...state,
        loading: true,
    },
    DELETE:{
        ...state,
        deleted: true
    },
    RESET: {
        ...state,
        confirmed: false,
        deleted: false,
        value: '',
    },
    WRITE:{
        ...state,
        value: action.payload
    }
});


const reducer = (state: State, action: Action) : State =>reducerObject(state, action)[action.type] || state;

export { UseReducer }
En el caso de estar trabajando con typescript creería que no es necesario los actionTypes, porque en la función reducer tipamos el parametro de action interface ActionType {    type: 'ERROR' | 'CHECK' | 'CONFIRM' | 'WRITE' | 'DELETE' | 'RESET',    payload?: string}