La mutación asíncrona de datos y su manejo son tareas necesarias en aplicaciones web modernas. Puede que desee ejecutar una función asíncrona independiente en el servidor para realizar tareas como guardar datos en el almacén de datos, enviar correos electrónicos, descargar archivos PDF, procesar imágenes, y cosas parecidas.
Next.js nos proporciona Acciones del Servidor
que son funciones asíncronas que se ejecutan en el servidor. Podemos usar acciones del servidor para mutaciones de datos en el servidor, pero las acciones del servidor se pueden invocar tanto desde componentes del servidor como desde componentes del cliente.
Las acciones del servidor son una gran manera de manejar los envíos de formularios ejecutando la acción cuando los datos del formulario se envían. En este artículo, examinaremos un caso práctico de cómo manejar argumentos adicionales en las acciones del servidor de Next.js.
Si está interesado en aprender acerca de las Acciones del Servidor de Next.js con patrones de diseño y construcción de proyectos, he creado un curso rápido para usted que puede encontrar aquí.
También este artículo está disponible como un tutorial de video aquí:
Tabla de Contenidos
¿Por Qué Necesitaría Pasar Argumentos Adicionales?
Cuando ejecutamos una acción del servidor en la entrega de un formulario, la acción del servidor recibe automáticamente los datos del formulario. Por ejemplo, echa un vistazo al formulario de abajo:
<form className="p-4 flex" action={updateUser}>
<Input className="w-1/2 mx-2" type="text" name="name" />
<Button type="submit">Update User Name</Button>
</form>
En este caso, estamos ejecutando una acción del servidor llamada updateUser
cuando el formulario es enviado. La función updateUser
recibirá los datos del formulario enviado como un argumento, que se puede usar para extraer los valores de los campos del formulario.
Como puede verse en el fragmento de código de abajo, la función updateUser
recibe un formData
como argumento, y podemos extraer el valor del campo name
de él.
"use server"
export async function updateUser(formData) {
const name = formData.get('name');
console.log(name);
}
Este patrón cubre la mayoría de los casos de uso básicos, pero puede que necesites pasar argumentos adicionales programáticamente a las acciones del servidor. Estos argumentos no forman parte del formulario o los datos del formulario o la entrada de datos del usuario. Pueden ser valores pasados programáticamente a tu acción del servidor.
Para entender esto, revisa el fragmento de código de la acción del servidor de abajo. Es la misma acción del servidor que hemos visto antes, pero hemos pasado un argumento adicional userId
junto con el argumento regular formData
.
"use server"
export async function updateUser(userId, formData) {
const name = formData.get('name');
console.log(userId);
console.log(name);
}
El valor de userId
es algo interno a la aplicación y no pedirías a un usuario que envíe el valor como parte de la presentación del formulario. En su lugar, podrías necesitar pasarlo programáticamente a tu acción del servidor para realizar cálculos adicionales.
Correcto, ese es el caso de uso del que estamos hablando. Como comprendemos por qué lo necesitamos, vamos a entender cómo lograrlo. Pero primero, vamos a crear un formulario y una acción del servidor funcional para él.
Un Formulario Con una Acción del Servidor
Crea un directorio llamado actions
dentro del directorio app
de tu aplicación Next.js. Ahora crea un archivo user.js
en la carpeta actions
con el siguiente código:
"use server"
export async function updateUser(formData) {
const name = formData.get('name');
console.log(name);
// Hacer cualquier cosa con el nombre, guardar en BD, crear factura, lo que sea!
}
Esto es cómo creas una función del servidor en Next.js. Debe tener una directiva ”use server”
en la parte superior del archivo para decirle a Next.js que este es un archivo especial con una o más funciones asíncronas que ejecutará en el servidor.
Tenemos entonces la acción del servidor (la función asíncrona) updateUser
con formData
como argumento. Dentro de la definición de la función, extraemos el valor de name
y lo imprimimos en la consola.
Ahora vamos a adjuntar esta acción del servidor a un formulario. Para ello, creamos una carpeta llamada components
en la carpeta raíz del proyecto. Creamos un archivo llamado user-form.jsx
con el siguiente código:
import { Input } from "./ui/input"
import { Button } from "./ui/button"
import { updateUser } from "@/app/actions/user"
const UserForm = () => {
return(
<form className="p-4 flex" action={updateUser}>
<Input className="w-1/2 mx-2" type="text" name="name" />
<Button type="submit">Update User Name</Button>
</form>
)
}
export default UserForm;
Este es un componente de React simple con un formulario. El formulario tiene un campo de texto de entrada llamado name
y un botón de envío para enviar el formulario. El formulario tiene un atributo action
con la acción del servidor updateUser
como valor. Ahora, cuando el formulario se envía con un valor de name
, la acción del servidor lo obtendrá como parte de los datos del formulario, como discutimos arriba.
Vamos a probarlo. Para ello, crearemos una ruta y página de Next.js donde podremos usar el componente UserForm
. Creamos una carpeta llamada extra-args
dentro del directorio app
. Ahora, creamos un archivo llamado page.js
dentro del directorio app/extra-args
con el siguiente código:
import UserForm from "@/components/user-form";
const ExtraArgsDemo = () => {
return (
<UserForm />
)
}
export default ExtraArgsDemo;
Este es un componente de React simple donde hemos importado el componente UserForm
y lo hemos usado en el JSX. Ahora ejecute el servidor local y acceda a esta ruta localhost:3000/extra-args
. Debería ver el formulario con un campo de texto y un botón.
Escriba algún texto dentro del campo de texto y haga clic en el botón.
Ahora, podrás ver que el texto tecleado ha sido impreso en la consola del servidor. ¿Por qué en la consola del servidor? ¿Por qué no en la consola del navegador? Esto es porque las acciones del servidor se ejecutan en el servidor, no en el lado del cliente del navegador.
Así, con esto hemos establecido un flujo de datos como este:
Página => Formulario => Acción del Servidor
La página tiene un formulario. El formulario ejecuta una acción del servidor al enviarse. La acción del servidor imprime datos del formulario en la consola del servidor.
Vamos a mejorar estos elementos para pasar argumentos adicionales a la acción del servidor.
Cómo pasar argumentos adicionales
Vamos a pasar una propiedad al componente UserForm
desde la página. Vamos a pasar un userId
con un valor para fingir que estamos pasando este userId programáticamente a nuestro formulario y a la acción del servidor desde allí.
import UserForm from "@/components/user-form";
const ExtraArgsDemo = () => {
return (
<UserForm userId={"1234"} />
)
}
export default ExtraArgsDemo;
En el componente UserForm
, aceptamos la propiedad userId
. Ahora, tenemos que hacer algo especial para pasar este userId a la acción del servidor updateUser
.
JavaScript tiene un método mágico llamado bind()
que nos ayuda a crear una Funcción Aplicada Parcialmente
. Con esta función aplicada parcialmente, puedes crear una función a partir de otra función con argumentos predefinidos.
En nuestro caso, la función updateUser
ya tiene un argumento llamado formData
. Ahora podemos pasar userId
como un argumento adicional utilizando el método bind()
para crear una nueva función.
const updatedUserWithId = updateUser.bind(null, userId);
El primer argumento del método bind()
es el contexto al que estás uniendo la función. El contexto maneja la asociación de la función con el valor de la palabra clave this
. En nuestro caso, podemos mantenerlo en null
ya que no lo estamos cambiando. Después de eso, hemos pasado el nuevo argumento userId
. Es bueno saber que el método bind()
funciona tanto en componentes del servidor como en componentes del cliente.
Aquí está el componente UserForm
modificado (archivo user-form.jsx
). Notar que el valor de acción del formulario ahora ha sido modificado para la nueva función updatedUserWithId
.
import { Input } from "./ui/input"
import { Button } from "./ui/button"
import { updateUser } from "@/app/actions/user"
const UserForm = ({userId}) => {
const updatedUserWithId = updateUser.bind(null, userId);
return(
<form className="p-4 flex" action={updatedUserWithId}>
<Input className="w-1/2 mx-2" type="text" name="name" />
<Button type="submit">Update User Name</Button>
</form>
)
}
export default UserForm;
Ahora, la acción del servidor recibirá el valor de userId
como un argumento. Vamos a imprimir eso en la consola del servidor también.
"use server"
export async function updateUser(userId, formData) {
const name = formData.get('name');
console.log(userId);
console.log(name);
// Hacer cualquier cosa con el id de usuario y el nombre, guardar en BD,
// crear factura, lo que sea!
}
Si envías el formulario con un valor de nombre:
Verás que tanto el userId como el valor del nombre se van a la consola del servidor. ¡Genial! Hemos registrado un valor del formulario y el otro se pasó internamente a la acción del servidor.
Así que aprendimos cómo pasar argumentos adicionales a la acción del servidor junto con los datos del formulario.
¿Qué pasa con los campos ocultos?
HTML admite un campo de formulario de tipo oculto para pasar datos del cliente al servidor sin aceptar la entrada de los usuarios. Esto significa que podríamos haber utilizado el campo oculto para pasar el valor de userId
de esta manera:
Entonces, ¿por qué hicimos todo eso con el método bind()
? Bueno, debido a preocupaciones de seguridad. Cuando pasas datos usando campos ocultos, el valor formará parte del HTML renderizado y no se codificará correctamente. Por lo tanto, es mejor manejarlo programáticamente.
Recursos
Eso es todo por ahora. ¿Disfrutaste leyendo este artículo y aprendiste algo nuevo? Si es así, me encantaría saber si el contenido fue útil. Permíteme compartir algunos recursos adicionales que puedas necesitar:
-
Todo el código fuente utilizado en este artículo está en mi GitHub.
-
Aquí tienes el Curso Intensivo sobre Acciones del Servidor con Patrones y Proyectos.
- Aquí tienes la Documentación Oficial de Acciones del Servidor si quieres leer más.
-
Y puedes leer más sobre el método bind() aquí.
Además, puedes conectarte conmigo por:
-
Suscribirte a mi Canal de YouTube. Si estás dispuesto a aprender
React
y su ecosistema, comoNext.js
, tanto conceptos básicos como proyectos, tengo una gran noticia para ti: puedes revisar este playlist en mi canal de YouTube con 25+ tutoriales en video y 15+ horas de contenido emocionante hasta la fecha, gratis. Espero que te gusten también. -
Sigueme en X (Twitter) o LinkedIn si no quieres perder la dosis diaria de consejos para mejorar tus habilidades.
-
Revisar y seguir mi trabajo de Código Abierto en GitHub.
-
Publico regularmente publicaciones significativas en mi GreenRoots Blog, puede que le resulten útiles también.
Nos vemos pronto con mi próximo artículo. Hasta entonces, cuídense bien y siga aprendiendo.
Source:
https://www.freecodecamp.org/news/how-to-pass-additional-arguments-to-nextjs-server-actions/