No tienes acceso a esta clase

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

Adquiere por un año todos los cursos, escuelas y certificados por un precio especial.

Antes: $249

Currency
$219/año

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Comprar ahora

Termina en:

0D
2H
27M
49S

Estados semideclarativos con useState

11/19
Recursos

Aportes 29

Preguntas 3

Ordenar por:

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

o inicia sesión.

Ejemplo de estado imperativo:

<button
   onClick={() =>
       setState({
           ...state,
           loading: true
       })
   }>Comprobar</button>

Ejemplo de estado declarativo:

const onCheck = () => {
   setState({
       ...state,
       loading: true
   })
}
 
...
<button
   onClick={() =>
       onCheck()
   }>Comprobar</button>

jajajajaj yo tambien me quedé pensando como se decia comprobar en Ingles xdd
Lo habia llamado onValidate ya que no recordaba.

En los botones simplemente puede ponerlo de esta manera

onClick={onCheck}

asi escribe menos codigo y es un poco mas entendible,
si la funcion recibe un parametro se debe hacer asi

onChange={(e) => onWrite(e)}

Codigo cada vez más declarativo:

  • Se usa funciones actualizadoras de estados con nombres muy informativos sobre el proceso.
  • Nos liberan de tener que indicar en cada parte del código principal cual es el nuevo proceso, estado o acción.

En mi experiencia, cuando estamos en los primeros pasos de desarrollando de una solución, el código tiende a ser más imperativo, buscando que la solución haga lo que necesitas, luego que ya tienes la solución, comienzas el proceso de refactorización y lo vuelves más declarativo. Es un proceso natural, además ayuda a reutilizar el código y también hacerlo más legible

state.value === SECURITY_CODE ? onConfirm() : onError();

He aprovechado y en vez de poner if-else lo he hecho en una linea.

El profe dice “acá arriba tenemos más líneas de código, pero acá abajo nuestro código se ve más limpio”.

Creo que el libro Clean Code se menciona algo como “(…) no pierdas tiempo escribiendo la documentación, escribe código que sea entendible a simple vista y luego documentas”.
Siento que el profe hace hincapié en eso cuando escribe:

if ( condition ) {
	onConfirm();
} else {
	onError();
}

Antes de ir a la siguiente clase yo trate de hacer a este componente lo mas declarativo que pude y este fue el resultado final del return

return (
    <div>
      <h2>{renderTitle(confirmation, deleted, name)}</h2>

      {renderContent(
        name,
        confirmation,
        deleted,
        validation,
        loading,
        state,
        setState
      )}
    </div>
  );

Obviamente la función renderContent, así como la de renderTitle son funciones que no agregue, pero estas funciones se encargan de toda la lógica por detrás para solo retornar el bloque de jsx que hay que regresar y la aplicación funciona bien

Código de la clase

const onConfirm = ()=>{
        setState({ 
            ...state,
            error: false, 
            loading: false ,
            confirmed: true,
        });
    }

const onError = ()=>{
        setState({ 
            ...state,
            error: true, 
            loading: false 
        });
    }    	

const onWrite = (event)=>{
        setState({ 
            ...state,
            value: event.target.value,
        });
    }

const onCheck = ()=>{
        setState({ 
            ...state,
            loading: true 
        });
    }

 const onDelete = ()=>{
        setState({
            ...state,
            deleted: true,
        })
    }

 const onReset = ()=>{
        setState({
            ...state,
            confirmed: false,
            deleted: false,
            value:'',
        })
    }
if(!state.deleted && !state.confirmed){
        return (
            <div>
                <h2>Eliminar {name}</h2>
                <p>Por favor, escriba el código de seguridad.</p>
    
                {(state.error && !state.loading ) && (
                    <p>El código es 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.confirmed && !state.deleted){
        return(
            <React.Fragment>
                <p>¿Seguro que quieres eliminar UseState?</p>
                <button
                    onClick={()=>{
                        onDelete();
                    }}
                >Si, eliminar</button>
                <button
                    onClick={()=>{
                        onReset();
                    }}
                >No, volver</button>
            </React.Fragment>
        )
    } else {
        return (
            <React.Fragment>
                <p>Eliminado con exito</p>
                <button
                    onClick={()=>{
                        onReset();
                    }}
                >Recuperar UseState</button>
            </React.Fragment>
        )
    }

Me encanta la forma semi-declarativa de usar estados!

por aqui dejo el link de platzi English Academy 🤣 :https://platzi.com/idioma-ingles/ 🤣

Básicamente, lo usamos para “optimizar” nuestro código y evitar el DRY (Don’t repeat your self)

La verdad es que quiza sea la costumbre o nolose, pero me acomodo mas con la primera forma, la Imperativa.

Por otro lado, me gustaría preguntar, ¿Cuando usar cualquiera de los dos enfoques.?

Intentando responderme solo y pensando en que dijo Juan que son igual de efectivos, supongno que es dependiendo de tu App como dijo y tambien de el equipo de trabajo con quien estes codeando. Y para concluir, aprender las dos formas.

Prefiero esta forma de programar, sinceramente

UseState: modo imperativo, en Nextj js, TypeScript, tailwind CSS y variables de entorno en .env.local

import React from "react";

const UseState = (props: { name: string }) => {
  const [state, setState] = React.useState({
    value: "",
    error: false,
    loading: false,
    deleted: false,
    confirmed: false,
  });
  const { name } = props;
  React.useEffect(() => {
    console.log("empezando el efecto");
    if (!!state.loading) {
      setTimeout(() => {
        console.log("haciendo la validación");
        if (state.value !== process.env.NEXT_PUBLIC_SECURITY_CODE) {
          setState({ ...state, error: true, loading: false });
        } else {
          setState({ ...state, error: false, loading: false, confirmed: true });
        }
        console.log("finalizando la validación");
      }, 1500);
    }
    console.log("finalizando el efecto");
  }, [state]);
  if (!state.deleted && !state.confirmed) {
    return (
      <section className="flex flex-col items-center w-screen h-96 justify-evenly">
        <h3 className="text-3xl font-bold">Eliminar {name}</h3>
        <p className="text-2xl ">Por favor, escribe el código de seguridad</p>
        {state.error && !state.loading && (
          <p className="text-xl font-medium text-red-600">
            error: el código es incorrecto
          </p>
        )}
        {state.loading && (
          <p className="text-xl font-medium text-green-600">...cargando</p>
        )}
        <div className="flex ">
          <input
            placeholder="Código de seguridad"
            className="p-2 mx-4 text-xl text-center border-2 rounded-md"
            value={state.value}
            onChange={(e) => {
              e.preventDefault();
              setState({ ...state, value: e.target.value });
            }}
          />
          <button
            className="p-2 text-xl font-semibold bg-green-200 border-2 border-green-700 rounded-md shadow-lg cursor-pointer text-slate-950 hover:bg-green-800 hover:text-slate-100"
            onClick={() => setState({ ...state, loading: true })}
          >
            Comprobar
          </button>
        </div>
      </section>
    );
  } else if (!!state.confirmed && !state.deleted) {
    return (
      <section className="flex flex-col items-center w-screen h-96 justify-evenly">
        <h2 className="mt-4 text-3xl font-bold text-center text-stone-800">
          ¿Seguro que quiere eliminar UseState?
        </h2>
        <div className="flex items-center mt-4 justify-evenly">
          <button
            className="px-4 py-2 mx-16 text-xl font-medium bg-red-600 border-2 rounded-lg shadow-lg text-stone-100"
            onClick={() => {
              setState({
                ...state,
                deleted: true,
              });
            }}
          >
            Si, eliminar
          </button>
          <button
            className="px-4 py-2 mx-16 text-xl font-medium bg-green-600 border-2 rounded-lg shadow-lg text-stone-100"
            onClick={() => {
              setState({
                ...state,
                confirmed: false,
                value: "",
              });
            }}
          >
            No, volver atrás
          </button>
        </div>
      </section>
    );
  } else {
    return (
      <section className="flex flex-col items-center w-screen h-96 justify-evenly">
        <h2 className="mt-4 text-3xl font-bold text-center text-stone-800">
          Eliminado con éxito
        </h2>
        <button
          className="px-4 py-2 mx-16 text-xl font-medium bg-green-600 border-2 rounded-lg shadow-lg text-stone-100"
          onClick={() => {
            setState({
              ...state,
              confirmed: false,
              deleted: false,
              value: "",
            });
          }}
        >
          Recuperar UseState
        </button>
      </section>
    );
  }
};

export default UseState;

No se que opinan si en vez de colocar varias funciones como onConfirm() y onError(), colocar una funcion por ejemplo onChangeState() y que esta sea la unica que maneje el cambio de estos estados. Por ejemplo algo asi:

    const onChangeState = (
    newValue = state.value,
    newError = state.error,
    newLoading = state.loading,
    newDeleted = state.deleted,
    newConfirmed = state.confirmed
  ) => {
    setState({
      value: newValue,
      loading: newLoading,
      error: newError,
      deleted: newDeleted,
      confirmed: newConfirmed,
    });
  };

De esta manera, cada vez que necesites actualizar un estado, realizas el llamado de esta funcion y envias unicamente los estados a actualizar, los que no envies simplemente mantendran su valor original por defecto.

En lugar del metodo onCheck yo lo llamé y me parece mejor onVerified

clean code ❤️

Para no confundirse mucho cuando se está haciendo la parte de la función onWrite

// La función recibe un evento de forma predeterminada al ser llamada, este se escribe como parámetro para poder utilizarla más adelante, y en el value le damos su valor que se encuentra en el target de ese evento.
const onWrite = (e) => {
  setState({
    ...state,
    value: e.target.value
  })
}
// Al escribir solo el nombre de la función, sin ejecutarla con los paréntesis estamos haciendo una referencia a esa función, en otras palabras sería como si la escribiéramos directamente, tiene el mismo comportamiento.
<input onChange={onWrite} />

Como tengo la extensión de ErrorLens, esta me indicaba que habría problemas de render por las dependencias de useEffect. Para evitar esto, necesitamos usar a useCallback.
En este artículo de Medium dan un ejemplo de cómo usarlos juntos

Y les dejo el código usando a ambos que funciona correctamente:

import { useState, useEffect, useCallback } from 'react'

import './UseState.css'

const SECURITY_CODE = 'techzone'

function UseState({name}) {
  const [state, setState] = useState({
    value: '',
    error: false,
    loading: false,
    deleted: false,
    confirmed: false,
  })

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

  const onCheck = () => {
    setState({
      ...state,
      loading: true
    })
  }

  const onDelete = () => {
    setState({
      ...state,
      deleted: true
    })
  }

  const onReset = () => {
    setState({
      ...state,
      confirmed: false,
      deleted: false,
      value: ''
    })
  }

  const changeState = useCallback(() => {
    const onConfirm = () => {
    setState({
      ...state,
      error: false,
      confirmed: true,
      loading: false
    })
  }

  const onError = () => {
    setState({
      ...state,
      error: true,
      loading: false
    })
  }

    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={(e) => onWrite(e.target.value)}
        />
        <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>
      </>
    )
  }
}

export { UseState }

Yo lo hice así

Validation lo ejecuta el button Confirmar

const validation = () => {
    setState({
      ...state,
      loading: true,
      error: false,
    });

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

  const toggleConfirm = (delValue, conValue) => {
    setState({
      ...state,
      deleted: delValue,
      confirm: conValue,
    });
  };
    
  const reStart = () => {
    setState({
      ...state,
      deleted: false,
      confirm: false,
      value: "",
    });
  };

Use effect

  setTimeout(() => {
      setState({
        ...state,
        error: state.value !== SECURITY_CODE,
        confirm: state.value === SECURITY_CODE,
        loading: false,
      });
    }, 1500);
  };

Algo de documentación sobre estos paradigmas: https://www.educative.io/blog/declarative-vs-imperative-programming

Hola a todos, espero esten teniendo un icreible dia de codigo devs!!. Les dejo mi solución para onCheck ya que considero que en el useEffect no es necesario hacer un if else.
.
Si opinas diferente porfavor dejame saberlo en los comentarios para aprender juntos desde diferentes puntos de vista!
.

.

Código de la clase en TypeScript

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

type Props = {
    name: string
}

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

const SECURITY_CODE = 'paradigma';


const UseState:FC<Props> = ({ name }) => {
    const [state, setState] = useState<State>({
        value: '',
        error: false,
        loading: false,
        confirmed: false,
        deleted: false,
    });

    const onConfirmed = () => {
        setState({
            ...state,
            loading: false,
            error: false,
            confirmed: true,
        })
    };

    const onError = ()=>{
        setState({
            ...state,
            loading: false,
            error: true,
        })
    };

    const onWrite = ({ target : { value }}:ChangeEvent<HTMLInputElement>)=>{
        setState({
            ...state,
            value
        })
    };

    const onCheck = ()=>{
        setState({
            ...state,
            loading: true
        })
    }

    const onDelete = ()=>{
        setState({
            ...state,
            deleted: true
        })
    };

    const onReset = ()=>{
        setState({
            ...state,
            confirmed: false,
            deleted: false,
            value: '',
        })
    };

    console.log(state.value);

    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>
            </>
        )
    }

}

export { UseState }

Desde mi punto de vista, realice algunos cambios en los actualizadores del estado value que se recibe del input y también como llamamos a cada uno de los estados mediante la desestructuración de objetos para evitar escribir siempre state.propiedad. A su vez en el useEffect utilice un operador ternario en la validación de la frase y asi mejorar la legibilidad del código quedando con la siguiente lógica:

const SECURITY_CODE = 'paradigma'

const UseState = ({ name }) =>{
    const [state, setState] = React.useState({loading: false, error: false, value: '', deleted: false, confirmed: false})
    const { loading, error, value, confirmed, deleted } = state

    const onConfirm = () =>{
        return setState({...state, loading: false, error: false, confirmed: true, value: ''})
    }

    const onError = () =>{
        return setState({...state, loading: false, error: true})
    }

    const onChangeValue = (value) =>{
        return setState({...state, value})
    }

    const onSubmit = () =>{
        return setState({...state, loading: !loading})
    }

    const onDelete = () =>{
        return setState({...state, deleted: true})
    }

    const onCancel = () =>{
        setState({...state, confirmed: false, deleted: false})
    }

    React.useEffect(()=>{
        if(loading){
            setTimeout(()=>{
                (value !== SECURITY_CODE)
                    ? onError()
                    : onConfirm()
            },3000)
        }
    }, [loading])

    if(!confirmed && !deleted){
        return (
            <div>
                <h2>Eliminar {name}</h2>
                <p>Por favor escribe el codigo de seguridad</p>
    
                {(!loading && !!error) && (<span>El codigo es incorrecto</span>)}
    
                {!!loading && (<span>Cargando</span>)}
    
                <input 
                value={value}
                placeholder="Codigo de seguridad"
                onChange={(event)=>onChangeValue(event.target.value)}/>

                <button onClick={onSubmit}>Comprobar</button>
            </div>
        )
    }else if(confirmed && !deleted){
        return (
            <>
                <p>Confirmacion de eliminacion, estas seguro?</p>
                <button onClick={onDelete}>Si, eliminar</button>

                <button onClick={onCancel}>No, cancelar</button>
            </>
        )
    }else{
        return (
            <>
                <p>Eliminado con exito</p>
                <button onClick={onCancel}>Recuperar SetState</button>
            </>
        )
    }
}

Mejorando mi propuesta anterior, se podría tener un método que se encargue de todos:

function handleUpdateState(nuevoEstado){
	return setMiEstadoCompuesto({
		...miEstadoCompuesto,
		...nuevoEstado
	})
}

Así podré actualizar uno o varios estado usando el mismo handle (handleUpdateState), por ejemplo:

handleUpdateState({ error: false })

ó

handleUpdateState({ error: false, loading: true, confirmed: true })

Código cada vez más declarativo:

  • Se usa funciones actualizadoras de estados con nombres muy informativos sobre el proceso.
  • Nos liberan de tener que indicar en cada parte del código principal cual es el nuevo proceso, estado o acción.

Para este ejemplo vamos a abstraer estos estados y crear un código más declarativo que nos indique a que pantalla vamos a cambiar.

dentro de el componente vamos a escribir lo siguiente:

function UseState({ name }) {
  const onConfirm = () => {
    setState({
      ...state,
      loading: false,
      confirmed: true,
    });
  }

  ...
}

Como vemos estamos abstrayendo los estados de React en una función que explica que de manera declarativa que es lo que estamos haciendo.

Ahora cada vez que deseemos llamar a este evento vamos a llamar a esta función.

React.useEffect(() => {
    if(state.loading) {
      setTimeout(() => {
        if(state.value === SECURITY_CODE) {
          onConfirm();
        } ...
      },3000);
    }
  }, [state.loading]);

Ya teniendo este conocimiento podemos empezar a hacer el resto con los demás, yo lo hice así:

function UseState({ name }) {
	const onChangeInput = (event) => {
    setState({
      ...state,
      value: event.target.value,
    });
  }

	const onSetUpValidate = () => {
    setState({
      ...state,
        error: false,
        loading: true,
      });
  }

  const onConfirm = () => {
    setState({
      ...state,
      loading: false,
      confirmed: true,
    });
  }

  const onError = () => {
    setState({
      ...state,
      loading: false,
      error: true,
    });
  }

  const onDelete = () => {
    setState({
      ...state,
      deleted: true,
    });
  }

  const onRepent = () => {
    setState({
      ...state,
      confirmed: false,
      deleted: false,
      value: '',
    })
  }
	 
	...
}

Esta es la manera en la que podemos tener un código un poco más declarativo.