Last active
November 11, 2025 01:19
-
-
Save warderer/5f5f634d306bc5614e7f5108187eaea9 to your computer and use it in GitHub Desktop.
[React Advanced Hooks Example Form] An example multistep form with useRef, useReducer and useCallback #devf #masterfrontend #introreact
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, | |
| Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; | |
| background-color: #f0f2f5; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| height: 100vh; | |
| margin: 0; | |
| } | |
| .form-container { | |
| background-color: #ffffff; | |
| padding: 2rem 3rem; | |
| border-radius: 12px; | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); | |
| width: 100%; | |
| max-width: 450px; | |
| min-height: 400px; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .form-step { | |
| animation: fadeIn 0.5s ease-in-out; | |
| } | |
| @keyframes fadeIn { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| h2 { | |
| color: #1c1e21; | |
| text-align: center; | |
| margin-bottom: 1.5rem; | |
| } | |
| .form-group { | |
| margin-bottom: 1.5rem; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| label { | |
| margin-bottom: 0.5rem; | |
| font-weight: 600; | |
| color: #4b4f56; | |
| } | |
| input { | |
| padding: 0.8rem; | |
| border: 1px solid #dddfe2; | |
| border-radius: 6px; | |
| font-size: 1rem; | |
| transition: border-color 0.2s, box-shadow 0.2s; | |
| } | |
| input:focus { | |
| border-color: #1877f2; | |
| box-shadow: 0 0 0 2px rgba(24, 119, 242, 0.2); | |
| outline: none; | |
| } | |
| .form-group small { | |
| color: #c0392b; | |
| margin-top: 0.25rem; | |
| } | |
| .form-navigation { | |
| display: flex; | |
| justify-content: space-between; | |
| margin-top: 2rem; | |
| gap: 1rem; | |
| } | |
| .form-navigation button { | |
| flex-grow: 1; | |
| padding: 0.8rem 1rem; | |
| font-size: 1rem; | |
| font-weight: 600; | |
| border-radius: 6px; | |
| border: none; | |
| cursor: pointer; | |
| transition: background-color 0.2s; | |
| background-color: #1877f2; | |
| color: white; | |
| } | |
| .form-navigation button.secondary { | |
| background-color: #e4e6eb; | |
| color: #4b4f56; | |
| } | |
| .form-navigation button:disabled { | |
| background-color: #a0b3d6; | |
| cursor: not-allowed; | |
| } | |
| .form-navigation button:not(:disabled):hover { | |
| filter: brightness(1.1); | |
| } | |
| .success { | |
| text-align: center; | |
| } | |
| .summary { | |
| background-color: #f0f2f5; | |
| border-radius: 8px; | |
| padding: 1rem; | |
| margin: 1.5rem 0; | |
| text-align: left; | |
| } | |
| .summary p { | |
| margin: 0.5rem 0; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // TODO: Importar useRef de React | |
| import { useEffect } from 'react' | |
| function Step1({ formData, handleFieldChange, nextStep }) { | |
| //TODO: Llamar a inputRef | |
| // | |
| useEffect(() => { | |
| //TODO: Enfoca el primer campo de entrada (nameInputRef) cuando el componente se monta | |
| }, []) | |
| const canProceed = formData.name && formData.email | |
| return ( | |
| <div className="form-step"> | |
| <h2>Paso 1: Información Personal</h2> | |
| <div className="form-group"> | |
| <label htmlFor="name">Nombre</label> | |
| <input | |
| type="text" | |
| id="name" | |
| name="name" | |
| ref={'ASIGNAMOS LA REFERENCIA AQUI'} | |
| value={formData.name} | |
| onChange={handleFieldChange} | |
| placeholder="Ej: César Guerra" | |
| /> | |
| </div> | |
| <div className="form-group"> | |
| <label htmlFor="email">Correo Electrónico</label> | |
| <input | |
| type="email" | |
| id="email" | |
| name="email" | |
| value={formData.email} | |
| onChange={handleFieldChange} | |
| placeholder="Ej: cesar.guerra@correo.com" | |
| /> | |
| </div> | |
| <div className="form-navigation"> | |
| <button onClick={nextStep} disabled={!canProceed}> | |
| Siguiente | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| export default Step1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // TODO: Importar useRef de React | |
| import { useEffect } from 'react' | |
| function Step2({ formData, handleFieldChange, prevStep, nextStep }) { | |
| //TODO: Llamar a inputRef | |
| useEffect(() => { | |
| //TODO: Enfoca el primer campo de entrada (passwordInputRef) cuando el componente se monta | |
| }, []) | |
| const canProceed = formData.password.length >= 8; | |
| return ( | |
| <div className="form-step"> | |
| <h2>Paso 2: Seguridad</h2> | |
| <div className="form-group"> | |
| <label htmlFor="password">Contraseña</label> | |
| <input | |
| type="password" | |
| id="password" | |
| name="password" | |
| ref={'ASIGNAMOS LA REFERENCIA AQUI'} | |
| value={formData.password} | |
| onChange={handleFieldChange} | |
| placeholder="Mínimo 8 caracteres" | |
| /> | |
| {!canProceed && formData.password && ( | |
| <small>La contraseña debe tener al menos 8 caracteres.</small> | |
| )} | |
| </div> | |
| <div className="form-navigation"> | |
| <button onClick={prevStep} className="secondary"> | |
| Anterior | |
| </button> | |
| <button onClick={nextStep} disabled={!canProceed}> | |
| Finalizar Registro | |
| </button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| export default Step2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function Success({ formData, reset }) { | |
| return ( | |
| <div className="form-step success"> | |
| <h2>¡Registro Exitoso!</h2> | |
| <p>Gracias por registrarte. Aquí está tu información:</p> | |
| <div className="summary"> | |
| <p><strong>Nombre:</strong> {formData.name}</p> | |
| <p><strong>Correo Electrónico:</strong> {formData.email}</p> | |
| </div> | |
| <div className="form-navigation"> | |
| <button onClick={reset}>Crear un nuevo registro</button> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| export default Success |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment