Recursos
Componentes no controlados
- uncontrolled: En la mayoría de los casos, te recomendamos usar Componentes controlados para implementar formularios.
- En un componente controlado, los datos del formulario son manejados por un componente React.
- La alternativa son los componentes no controlados, donde los datos del formulario son manejados por el propio DOM.
- Para escribir un componente no controlado, puedes usar una referencia para que obtengas los valores del formulario desde el DOM.
Referencias y el DOM
refs: Las referencias proporcionan una forma de acceder a los nodos del DOM o a elementos React creados en el método de renderizado.
useRef: useRef devuelve un objeto ref mutable cuya propiedad .current
se inicializa con el argumento pasado (initialValue). El objeto devuelto se mantendrá persistente durante la vida completa del componente.
components/Header.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| const logo = "./src/assets/react.svg";
const Header = () => {
return (
<>
<h1 className="text-info text-center">Formularios en React</h1>
<img className="rounded d-block mx-auto" src={logo} />
<hr></hr>
</>
);
}
export default Header;
|
components/NoControlado.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| const NoControlado = () => {
// Formulario no controlado
const handleSubmit = () => {
console.log("Formulario enviado");
};
return (
<div className="container mt-2">
<form
onSubmit={handleSubmit}
>
<input
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoNombre"
defaultValue="Tarea #01"
/>
<textarea
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoDescripcion"
defaultValue="Descripción tarea #01"
/>
<select
className="form-control mb-2"
name="todoEstado"
defaultValue="completado"
>
<option value="pendiente">Pendiente</option>
<option value="completado">Completado</option>
</select>
<button
className="btn btn-primary"
type="submit"
>
Agregar
</button>
</form>
</div>
);
};
export default NoControlado;
|
App.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| import NoControlado from "./components/FormularioNoControlado";
import Header from "./components/Header";
const App = () => {
return (
<div className="container">
<Header/>
<div className="row">
<NoControlado/>
</div>
</div>
);
};
export default App;
|
- Prevent Default modificar
NoControlado.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| const NoControlado = () => {
// Formulario no controlado
const handleSubmit = (e) => {
console.log("Formulario enviado");
console.log(formulario.current);
e.preventDefault();
};
/* document.addEventListener("submit", (evento) => {
evento.preventDefault();
}); */
return (
<div className="col-sm-6">
<form
onSubmit={handleSubmit}
/*onSubmit={(e) => handleSubmit(e)}*/
>
<input
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoNombre"
defaultValue="Tarea #01"
/>
<textarea
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoDescripcion"
defaultValue="Descripción tarea #01"
/>
<select
className="form-select mb-2"
name="todoEstado"
defaultValue="pendiente"
>
<option value="pendiente">Pendiente</option>
<option value="completado">Completado</option>
</select>
<button
className="btn btn-info"
type="submit"
>
Agregar
</button>
</form>
</div>
);
};
export default NoControlado;
|
- Usualmente para capturar los datos de un formulario se debe de usar un id al mismo. sin embargo esto daria problemas con el DOM virtual de React. Por lo que usamos un hook llamado useRef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
| import { useRef } from "react";
const NoControlado = () => {
const formulario = useRef(null);
// Formulario no controlado
const handleSubmit = (e) => {
console.log("Formulario enviado");
console.log(formulario.current);
e.preventDefault();
};
/* document.addEventListener("submit", (evento) => {
evento.preventDefault();
}); */
return (
<div className="col-sm-6">
<form
onSubmit={handleSubmit}
ref={formulario}
>
<input
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoNombre"
defaultValue="Tarea #01"
/>
<textarea
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoDescripcion"
defaultValue="Descripción tarea #01"
/>
<select
className="form-select mb-2"
name="todoEstado"
defaultValue="pendiente"
>
<option value="pendiente">Pendiente</option>
<option value="completado">Completado</option>
</select>
<button
className="btn btn-info"
type="submit"
>
Agregar
</button>
</form>
</div>
);
};
export default NoControlado;
|
- modificar
NoControlado.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
| import { useRef, useState } from "react";
const NoControlado = () => {
const formulario = useRef(null);
const [error, setError] = useState(null);
// Formulario no controlado
const handleSubmit = (e) => {
console.log("Formulario enviado");
//console.log(formulario.current);
e.preventDefault();
setError(null);
//?Capturar datos del formulario
// El método FormData() crea un objeto FormData que representa un conjunto de pares clave/valor.
const datos = new FormData(formulario.current);
// spread operator: permite a un elemento iterable ser expandido
// copia cada uno de sus elementos
console.log([...datos.entries()]);
// El método Object.fromEntries() transforma una lista de pares con [clave-valor] en un objeto.
const objetoDatos = Object.fromEntries([...datos.entries()]);
console.log(objetoDatos);
//?Validaciones
if (!objetoDatos.todoNombre.trim()) {
return console.log("Campo vacío");
}
if (!objetoDatos.todoNombre.trim() || !objetoDatos.todoDescripcion.trim() || !objetoDatos.todoEstado.trim()) {
return setError("* Llena todos los campos");
}
console.log("Pasó las validaciones!");
formulario.current.reset();
};
/* document.addEventListener("submit", (evento) => {
evento.preventDefault();
}); */
return (
<div className="col-sm-6">
<h2 className="text-info">Formulario No Controlado</h2>
<form
onSubmit={handleSubmit}
//onSubmit={(e) => handleSubmit(e)}
ref={formulario}
>
<input
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoNombre"
defaultValue="Tarea #01"
/>
<textarea
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoDescripcion"
defaultValue="Descripción tarea #01"
/>
<select
className="form-select mb-2"
name="todoEstado"
defaultValue="pendiente"
>
<option value="pendiente">Pendiente</option>
<option value="completado">Completado</option>
</select>
<button
className="btn btn-info"
type="submit"
>
Agregar
</button>
{error !== "" &&
<>
<hr></hr>
<span className="text-warning">{error}</span>
</>
}
</form>
</div>
);
};
export default NoControlado;
|
Componentes controlados
- controlled
- Los componentes React que renderizan un formulario también controlan lo que pasa en ese formulario con las subsecuentes entradas del usuario.
- Ahora vamos a poder detectar los campos input en tiempo real.
components/Controlado.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| const Controlado = () => {
// Formulario controlado
const handleSubmit = (e) => {
e.preventDefault();
};
return (
<div className="col-sm-6">
<h2 className="text-info">Formulario Controlado</h2>
<form
onSubmit={handleSubmit}
>
<input
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoNombre"
/>
<textarea
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoDescripcion"
/>
<select
className="form-select mb-2"
name="todoEstado"
>
<option value="pendiente">Pendiente</option>
<option value="completado">Completado</option>
</select>
<button
className="btn btn-info"
type="submit"
>
Agregar
</button>
</form>
</div>
);
};
export default Controlado;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| import { useState } from "react";
const Controlado = () => {
const [todoNombre, setTodoNombre] = useState("Tarea #1");
const [todoDescripcion, setTodoDescripcion] = useState("Descripción tarea #01");
const [todoEstado, setTodoEstado] = useState("pendiente");
// Formulario controlado
const handleSubmit = (e) => {
e.preventDefault();
console.log(todoNombre, todoDescripcion, todoEstado)
};
return (
<div className="col-sm-6">
<h2 className="text-info">Formulario Controlado</h2>
<form
onSubmit={handleSubmit}
>
<input
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoNombre"
value={todoNombre}
onChange={(e) => setTodoNombre(e.target.value)}
/>
<textarea
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoDescripcion"
value={todoDescripcion}
onChange={(e) => setTodoDescripcion(e.target.value)}
/>
<select
className="form-select mb-2"
name="todoEstado"
value={todoEstado}
onChange={(e) => setTodoEstado(e.target.value)}
>
<option value="pendiente">Pendiente</option>
<option value="completado">Completado</option>
</select>
<button
className="btn btn-info"
type="submit"
>
Agregar
</button>
</form>
</div>
);
};
export default Controlado;
|
- Variante con
useState
como objeto y funcion para manejar el OnChange
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
| import { useState } from "react";
const Controlado = () => {
const [todo, setTodo] = useState({
todoNombre: "Tarea #01",
todoDescripcion: "Descripción tarea #01",
todoEstado: "pendiente",
});
// Formulario controlado
const handleSubmit = (e) => {
e.preventDefault();
console.log(todo)
};
const handleOnChange = (e) => {
// console.log(e.target.name);
// console.log(e.target.value);
// setTodo({ ...todo, [e.target.name]: e.target.value });
// utilizando el callback
setTodo((todo) => ({
...todo,
[e.target.name]: e.target.value,
}));
};
return (
<div className="col-sm-6">
<h2 className="text-info">Formulario Controlado</h2>
<form
onSubmit={handleSubmit}
>
<input
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoNombre"
value={todo.todoNombre}
onChange={handleOnChange}
/>
<textarea
className="form-control mb-2"
type="text"
placeholder="Ingrese un TODO"
name="todoDescripcion"
value={todo.todoDescripcion}
onChange={handleOnChange}
/>
<select
className="form-select mb-2"
name="todoEstado"
value={todo.todoEstado}
onChange={handleOnChange}
>
<option value="pendiente">Pendiente</option>
<option value="completado">Completado</option>
</select>
<button
className="btn btn-info"
type="submit"
>
Agregar
</button>
</form>
</div>
);
};
export default Controlado;
|