No tienes acceso a esta clase

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

Estados semideclarativos con useState

11/19
Recursos

Aportes 33

Preguntas 3

Ordenar por:

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

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>

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

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

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

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.

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

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

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

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

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.

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

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

Estados semideclarativos con useState

.
Hasta ahora recalcamos que hemos estado trabajando de forma imperativa, por lo que ahora vamos a tratar de ser un poco más declarativos.
.
Es decir, no nos centraremos en el paso a paso de cómo debería cambiar el estado, sino que vamos a abstraer esa lógica y simplemente llamarla desde dónde la necesitemos.
.
Lo primero que hacemos es crear unos métodos actualizadores del estado.
.

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

const onError = () => {
  setState({
    ...state,
    error: true,
    loading: 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: '',
  });
};

.
Estos métodos viene a remplazar lo que ya teníamos anteriormente en el componente, solo que ahora los abstraemos en funciones flechas que llamaremos desde dónde corresponde.
.

function UseState({ name }) {
  ...

  React.useEffect(() => {
    console.log("Empezando el efecto")

    if (!!state.loading) {
      setTimeout(() => {
        console.log("Haciendo la validación")
  
        if (state.value === SECURITY_CODE) {
          onConfirm();
        } 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.</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={(event) => {
            onWrite(event.target.value);
          }}
        />
        <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>
    );
  }
}

.
Algunas ulteriores modificaciones que podemos destacar son que:
.

  • En el botón de Nop, me arrepentí teníamos un cambio de estado muy similar al de Resetear, volver atrás, por lo que hemos concluido en utilizar un mismo método actualizador para ambos.
    .
  • Nuestro imput para ingresar el código de seguridad necesita recibir un evento, por lo que en el método actualizador onWrite utilizamos una función flecha que nos permite capturar el evento y mandar a event.target.value como parámetro onWrite. A estos tipo de parámetros lo llamaremos payload cuando veamos useReducer.
```js const onConfirm = () => { setState({ ...state, error: state.value !== SECURITY_CODE, loading: false, confirmed: state.value === SECURITY_CODE, }); } ``````js useEffect(() => { if (!!state.loading) setTimeout(onConfirm, 1500); }, [state.loading]); ```
los sedaos semidaclarativos también nos ayudan a reutilizar código!!

Así maneje el mio, los componentes que vienen desde /Styles están usando Styled Components.

index.js

import React, { useState, useEffect } from 'react';
import SECURITY_CODES from '../../SECURITY_CODES';
import { Section, Heading2, Paragraph, InputContainer } from '../Styled';
import { VerifyContent, ConfirmButtons, RecoverButton } from './ContentActions';

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

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

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

  useEffect(() => {
    if (!!state.loading) {
      setTimeout(() => {
        const matchCode = SECURITY_CODES.some(code => state.value.toUpperCase() === code);
        if (matchCode) {
          onValidCode();
        } else {
          onInvalideCode();
        }
      }, 3000);
    }
  }, [state.loading, state.value]);

  const handleChangeValue = inputValue => {
    setState(prevstate => {
      return { ...prevstate, value: inputValue, error: inputValue.length === 0 };
    });
  };

  const handleCheck = () => {
    setState(prevstate => ({
      ...prevstate,
      error: false,
      loading: !prevstate.loading,
    }));
  };

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

  const handleConfirm = () => {
    setState(prevstate => ({ ...prevstate, deleted: true }));
  };

  return (
    <Section>
      <Heading2>Eliminar {name}</Heading2>
      <Paragraph>
        {state.confirmed && !state.deleted
          ? '¿Estas seguro que deseas eliminar el estado?'
          : state.deleted
          ? 'Estado eliminado correctamente'
          : !state.loading &&
            'Por favor, escribe el código de seguridad para comprobar que quieres eliminar el estado.'}
      </Paragraph>

      {state.loading ? (
        <Paragraph variant="loading">Estamos verificando</Paragraph>
      ) : (
        <InputContainer>
          {!!state.deleted && !!state.confirmed && <RecoverButton onRecover={handleReset} />}
          {!!state.confirmed && !state.deleted && <ConfirmButtons onReject={handleReset} onConfirm={handleConfirm} />}
          {!state.confirmed && !state.deleted && (
            <VerifyContent state={state} onChange={e => handleChangeValue(e.target.value)} onCheck={handleCheck} />
          )}
        </InputContainer>
      )}
    </Section>
  );
};

export { UseState };

RecoverButton

import { Button } from '../../Styled';

const RecoverButton = ({ onRecover }) => <Button onClick={onRecover}>Recuperar el Estado</Button>;

export { RecoverButton };

ConfirmButtons

import { Button } from '../../Styled';

const ConfirmButtons = ({ onReject, onConfirm }) => (
  <>
    <Button onClick={onReject}>Rechazar</Button>
    <Button onClick={onConfirm}>Confirmar</Button>
  </>
);

export { ConfirmButtons };

VerifyContent

import { Paragraph, Input, Button } from '../../Styled';

const VerifyContent = ({ state, onChange, onCheck }) => {
  return (
    <>
      <Input value={state.value} placeholder="Código de Seguridad" onChange={onChange} />
      {state.error && <Paragraph variant="error">El código es incorrecto</Paragraph>}
      <Button onClick={onCheck}>Comprobar</Button>
    </>
  );
};

export { VerifyContent };

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.