Introducción
Manejo Avanzado del Estado en React.js
Estado y ciclo de vida con React.Component
Creación de Proyectos React y Manejo de Estado con Hooks y Clases
Diferencias entre Componentes de Clase y Función en React
Efectos y ciclo de vida en componentes React con useEffect
Métodos del ciclo de vida en componentes de clase React
Estados independientes y compuestos
Diferencias entre estados simples y compuestos en React
Actualización de estados en interfaces de usuario con React
Estados Compuestos en Componentes de Clase con React
Estados Compuestos con React.UseState: Manejo y Actualización Eficiente
Código imperativo y declarativo en React
Programación Imperativa vs Declarativa: Implementación en React
Programación Declarativa: Simplificación y Abstracción de Estados
Uso de UseReducer para manejar el estado en React
Creación de Reducers: If, Switch y Reducer Objects en React
Manejo de estados con useReducer en React
Manejo de Action Types y Action Creators en React Reducers
Manejo del estado en TODO Machine
Manejo de Estados Derivados en React con useState
Migración de UseState a UseReducer en React
Optimización de Custom Hooks en React sin UseReducer
Próximos pasos
Manejo Profesional del Estado en React con Hooks y Reducers
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Aportes 44
Preguntas 3
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
Action creators:
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.
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
.
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’
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 }
```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.
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 (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>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 ( \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> \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 }; ````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> \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 };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> \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 };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 }
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?