Como React es solo una biblioteca, no dicta reglas sobre cómo debe organizar y estructurar sus proyectos. Esto es bueno, porque nos da la libertad de probar diferentes enfoques y adaptar los que mejor se adapten a nosotros. Por otro lado, esto podría generar cierta confusión para los desarrolladores que se inician en el mundo de React .
En esta publicación, mostraré algunos enfoques que he estado usando durante un tiempo y se han escalado muy bien. Estos enfoques no recrean la rueda, simplemente juntan y refinan lo que tenemos en el mercado.
Recuerda: ¡Nada aquí está escrito en rocas! Puede tomar solo los enfoques que crea que tienen sentido y adaptarlos/cambiarlos para que encajen en su contexto.
Una de las preguntas que veo a menudo es sobre cómo estructurar archivos y carpetas. En esta publicación, estamos considerando que tiene una estructura mínima, como la creada con create-react-app.
La aplicación create-react genera un proyecto básico para nosotros, que contiene en su raíz los archivos: .gitignore , package.json , README.md , yarn.lock
También genera las carpetas: public y src. El último es donde guardamos nuestro código fuente.
Echa un vistazo a la imagen de abajo, con la estructura descrita:
En esta publicación, nos centraremos en la carpeta src. Todo lo que está fuera de eso, permanecerá intacto.
Es probable que ya haya visto la separación entre Contenedores y Componentes de presentación en la carpeta raíz de algún proyecto. quiero decir, dentro
src
, tienes una carpeta llamada components
y otra carpeta llamada containers
: Sin embargo, este tipo de enfoque tiene algunos problemas, como puede ver a continuación:
También hay una variación de ese enfoque, que mantiene esta separación, pero dentro de los módulos.
Imagina que dentro de tu aplicación tienes el módulo Usuario. En su interior, tendrías dos carpetas para separar tus componentes:
El enfoque anterior minimiza el problema de navegar entre carpetas distantes en el árbol del proyecto. Sin embargo, añade mucho ruido. Dependiendo de cuántos módulos tenga su aplicación, terminará con docenas de contenedores y carpetas de componentes.
Por esos motivos, cuando hablamos de organizar carpetas y archivos, es irrelevante dividir nuestros componentes por el concepto de presentación frente a contenedor. Que dicho , vamos a mantener todos nuestros componentes dentro de la carpeta de componentes, excepto las pantallas .
Aun siendo irrelevante separarlos en carpetas, es importante conocer la diferencia conceptual entre uno y otro. Si aún tiene preguntas sobre este tema, le sugiero que lea el artículo: Componentes de presentación y contenedores.
Dentro de la carpeta de componentes, agrupamos los archivos por módulo/característica.
En un CRUD de usuario, solo tendríamos el módulo Usuario. Entonces, nuestra estructura sería la siguiente:
Cuando un componente está compuesto por más de un archivo, colocamos este componente y sus archivos en una carpeta con el mismo nombre. Por ejemplo: supongamos que tiene un Form.css que contiene los estilos de Form.jsx. En este caso, su estructura sería así:
Los archivos de prueba permanecen con el archivo que se está probando. En el caso anterior, la prueba para Form.jsx permanecería en su misma carpeta y se llamaría Form.spec.jsx
Más allá de separar los componentes por módulos, también incluimos una carpeta UI dentro de src/components, para guardar todos nuestros componentes genéricos en ella.
Los componentes de la interfaz de usuario son componentes lo suficientemente genéricos como para no pertenecer a un módulo. Son componentes que podría mantener en una biblioteca de código abierto, porque no tienen ninguna lógica comercial de la aplicación específica. Ejemplos de esos componentes son: botones, entradas, casillas de verificación, selecciones, modales, elementos de visualización de datos, etc.
Arriba vimos cómo estructurar carpetas y separar nuestros componentes por módulos. Sin embargo, todavía hay una pregunta: ¿Cómo nombrarlos?
Cuando hablamos de nombrar un componente, se trata del nombre que le damos a la clase o a la const que define el componente:
class MyComponent extends Component { } const MyComponent () => {};
Como se mencionó anteriormente, el nombre que le demos a los componentes, debe ser claro y único en la aplicación, para que sean más fáciles de encontrar y evitar posibles confusiones.
El nombre de un componente es muy útil cuando necesitamos depurar usando herramientas como React Dev Tools y cuando ocurren errores de tiempo de ejecución en la aplicación. El error siempre viene con el nombre del componente donde ocurrió.
Para nombrar los componentes, seguimos el patrón path-based-component-naming, que consiste en nombrar el componente de acuerdo a su ruta relativa a las carpetas components oa src, en el caso de que se encuentre fuera de la carpeta de componentes. Básicamente, un componente que se encuentra en: componentes/Usuario/
List.jsx
sería nombrado como UserList
.Cuando el archivo está dentro de una carpeta con el mismo nombre, no necesitamos repetir el nombre. Dicho esto, componentes/Usuario/Formulario/
Form.jsx
, sería nombrado como UserForm
y no como UserFormForm
.El patrón anterior tiene algunos beneficios que podemos ver a continuación:
Si su editor es compatible con la búsqueda difusa, simplemente busque el nombre UserForm para encontrar el archivo correcto:
Si desea buscar el archivo en el árbol de carpetas, puede encontrarlo fácilmente simplemente orientándose por el nombre del componente:
Siguiendo el patrón, siempre nombrará el archivo de acuerdo con su contexto. Teniendo en cuenta el formulario anterior, sabemos que es un formulario de usuario , pero como ya estamos dentro de la carpeta Usuario , no necesitamos repetir esa palabra en el nombre del archivo del componente. Entonces, lo nombramos solo como Form.jsx
Cuando comencé a trabajar con React , solía poner el nombre completo en el archivo. Sin embargo, eso te hace repetir un nombre muchas veces y la ruta de importación se vuelve demasiado grande. Echa un vistazo a la diferencia entre los enfoques:
En el ejemplo anterior, no puede ver la ventaja de un enfoque a otro. Pero la aplicación crece un poco, es posible ver la diferencia. Mire el ejemplo a continuación, considerando un componente del proyecto en el que trabajo:
Ahora imagine esto multiplicado por 5 o 10 veces en un solo archivo.
Por esa razón, siempre nombramos el archivo de acuerdo con su contexto y el componente de acuerdo con su ubicación relativa a
components
o src
carpeta.Las pantallas, como ya indica el nombre, serían las pantallas que tenemos en la aplicación.
En un CRUD de usuarios, tendríamos una pantalla para la lista de usuarios, una pantalla para crear un nuevo usuario y una pantalla para editar un usuario existente.
Una pantalla es donde utiliza componentes para componer una página para la aplicación. Idealmente, la pantalla no contendría ninguna lógica y sería un componente funcional.
Mantenemos las pantallas en una carpeta separada en la raíz de src, porque se agruparán de acuerdo con la definición de la ruta y no por módulos:
Teniendo en cuenta que el proyecto usa react-router , mantenemos el archivo Root.jsx dentro del
screens
carpeta, y definimos en ella todas las rutas de la aplicación.El código para Root.jsx sería similar a este:
import React, { Component } from 'react' ; import { Router } from 'react-router' ; import { Redirect, Route, Switch } from 'react-router-dom' ; import ScreensUserForm from './User/Form' ; import ScreensUserList from './User/List' ; const ScreensRoot = () => ( < Router > <Switch> <Route path="/user/list" component={ScreensUserList} /> <Route path="/user/create" component={ScreensUserForm} /> <Route path="/user/:id" component={ScreensUserForm} /> </Switch> </Router> ); export default ScreensRoot;
Fíjate que ponemos todas las pantallas dentro de una carpeta con el mismo nombre de la ruta, usuario/ -> Usuario/. Trate de mantener una carpeta para cada ruta principal y agrupe las subrutas en ella. En este caso, creamos la carpeta Usuario y guardamos en ella la Lista de pantallas y el Formulario de pantalla. Este patrón te ayudará a encontrar fácilmente qué pantalla está representando cada ruta, simplemente echando un vistazo a la url.
Se podría usar una sola pantalla para representar dos rutas diferentes, como hicimos anteriormente con las rutas para crear y editar un usuario.
Puede notar que todos los componentes contienen la pantalla como prefijo en su nombre. Cuando el componente se encuentra fuera de la carpeta de componentes, debemos nombrarlo de acuerdo con su ruta relativa a la carpeta src. Un componente ubicado en src/screens/User/List.jsx debe llamarse ScreensUserList.
Con el Root.jsx creado, nuestra estructura sería la siguiente:
No olvide importar Root.jsx dentro de index.js para que sea el componente raíz de la aplicación.
En caso de que aún tenga dudas sobre cómo debe verse una pantalla, eche un vistazo al ejemplo a continuación, para ver cuál sería la pantalla para el formulario de usuario.
import React from 'react' ; import UserForm from '../../components/User/Form/Form' ; const ScreensUserForm = ( { match: { params } } ) => ( < div > <h1> {`${!params.id ? 'Create' : 'Update'}`} User </h1>
<UserForm id={params.id} /> </div> ); export default ScreensUserForm;
Finalmente, nuestra aplicación quedaría estructurada así:
Los consejos anteriores cubren solo una parte de la organización y estructura de un proyecto. Traté de mantenerlo solo sobre React y dejar Redux para una publicación futura.
¿Y usted? ¿Tienes algún enfoque que te gustaría compartir con nosotros? Escribe una respuesta a continuación, ¡me encantaría leer eso!
¿Disfrutaste la lectura? Ayúdanos a correr la voz dando un me gusta y compartiendo ️️️️ ❤️️
¡No olvides seguirme para recibir notificaciones sobre futuras publicaciones!