Creación de componentes\n
Antes de comenzar
En la mayoría de los casos, los componentes de Jutro deberían satisfacer los requisitos que usted tenga. Sin embargo, quizás desee crear componentes para organizar el código y componer las páginas. Usted crea sus propios componentes en estas situaciones:
- Desea gestionar el estado o la configuración compleja de un componente de Jutro.
- Desea encapsular su lógica personalizada en un componente.
- Desea agrupar varios componentes en un widget que satisfaga una necesidad particular, en especial si quiere reutilizar ese widget en varios lugares.
- Está agregando una página a su aplicación. Se recomienda encapsular la página en un componente de React y utilizarla en su plano de planta.
El componente personalizado puede ser uno de estos:
Componentes extendidos
Para extender un componente de Jutro, puede encapsularlo en un componente de usted. Puede hacer esto para establecer propiedades predeterminadas o controladores de eventos. Este componente hereda la localización, la accesibilidad y otras funciones relevantes.
Por ejemplo, podría crear un campo FavoriteBook en el que el rótulo diga “Libro favorito” y siempre se aplique un estilo específico.
import { TextInput } from '@jutro/components';
import messages from './FavoriteBook.messages.js';
import styles from './FavoriteBook.module.scss';
. . .
const FavoriteBook = () => {
return (
<TextInput
label="Favorite Book"
placeholder="What is your favorite book?"
classname="favoritebook"
/>
);
};
Componentes compuestos
Puede crear componentes nuevos agrupando los componentes existentes de Jutro, los componentes extendidos y componentes personalizados. Estos componentes “compuestos” heredan todas las funciones pertinentes de los componentes de Jutro que utilizan.
Por ejemplo, cree un componente personalizado llamado ControlCenter que utilice componentes de Jutro como Card, NumberValuenumber, Grid o Icon con algunas propiedades personalizadas y el mecanismo de localización para mostrar algo de clientInformation específico.
import { Card, NumberValue, Icon } from '@jutro/components';
import { Grid, GridItem } from '@jutro/layout';
import messages from './ControlCenter.messages.js';
export const ControlCenter = (props) => {
const icon =
props.daysSince < 7
? 'gw-error'
: props < 30
? 'gw-warning'
: 'gw-check-circle';
const style =
props.daysSince < 7
? { color: 'red' }
: props.daysSince < 30
? { color: 'orange' }
: { color: 'green' };
return (
<Card
title={messages.heading}
style={style}>
<Grid columns={['1fr', '1fr']}>
<GridItem>
<Icon icon={icon} />
</GridItem>
<GridItem>
<NumberValue
id="daysSince"
value={props.daysSince}
suffix={messages.dayssince}
/>
</GridItem>
</Grid>
</Card>
);
};
Prácticas recomendadas para crear un componente nuevo
Cuando cree componentes nuevos, cumpla estas pautas generales:
-
No codifique texto de forma rígida en sus componentes. Almacene strings de traducción en
ComponentName.messages.jse impórtelos mediante:import messages from './ComponentName.messages.js'; -
Agregue estilos en un archivo
ComponentName.module.scsse impórtelos usando:import styles from './ComponentName.module.scss'; -
Recomendamos utilizar componentes funcionales en lugar de componentes de clase porque:
- Los componentes funcionales son mucho más fáciles de leer y probar porque son funciones simples de JavaScript sin ganchos de estado o ciclo de vida.
- Tiene menos código.
- Lo ayudan a utilizar las prácticas recomendadas. Será más fácil separar los componentes contenedor y de presentación, ya que tendrá que pensar más en el estado de su componente si no tiene acceso a
setState()en su componente.
Haga clic aquí para obtener más información acerca de los componentes funcionales.
Creación de la estructura de carpetas
Cree un directorio en src/Components para el componente, por ejemplo CustomInput, y agréguele los siguientes archivos:
src/components/CustomInput/CustomInput.test.tsxsrc/components/CustomInput/CustomInput.tsxsrc/components/CustomInput/CustomInput.messages.tssrc/components/CustomInput/CustomInput.module.scss
Seguir esta convención de nomenclatura facilitará las actualizaciones en el futuro.
Creación del componente
- En el directorio
CustomInput, cree el archivo<componentName>.tsx, en este ejemplo:./CustomInput.tsx. - El código para el componente
CustomInputdebe encargarse de:- propiedades esperadas (
PropTypes) y sus valores; - funciones de gestión de estado utilizando las funciones
writeValueyreadValue.writeValuedebe tomar el valor del componentetestInput, restablecer el estado del componente y el valor de salida detestInputen el componentetestOutput.
- propiedades esperadas (
import React, { useContext } from 'react';
import { useTranslator } from '@jutro/locale';
import styles from './CustomInput.module.scss';
import messages from './CustomInput.messages.ts';
type CustomInputProps = {
title?: string,
};
export const CustomInput: React.FC<CustomInputProps> = ({ title }) => {
const translator = useTranslator();
return (
<div
className={styles.customInput}
title={title}>
{translator(messages.label)}
</div>
);
};
Creación del archivo de mensajes (opcional)
Como se menciona en la sección Prácticas recomendadas, no se recomienda que el componente tenga texto codificado, por ello, quizás sea necesario crear el archivo de mensajes para almacenar los strings de traducción.
import { defineMessages } from 'react-intl';
export default defineMessages({
label: {
id: 'jutro-app.components.CustomInput.label',
defaultMessage: 'custom inputLabel',
},
});
Consulte la sección Internacionalización y localización para obtener más información.
<ComponentName>.messages.js.Creación del archivo StyleSheet (opcional)
En caso de que necesite un estilo adicional, puede definirlo dentro del archivo ./CustomInput.module.scss.
<ComponentName>.module.scss.Pruebas de accesibilidad al componente
Asegúrese de que el componente cumpla, al menos, los requisitos básicos de accesibilidad:
- Está disponible para lectores de pantalla.
- Se puede navegar por él mediante el teclado.
- Tiene el contraste adecuado.
Puede obtener más información en nuestra página sobre accesibilidad.
Redacción de pruebas para sus componentes
Para que su componente siga funcionando durante mucho tiempo, asegúrese de redactar pruebas completas y bien pensadas. Puede obtener más información en nuestra sección integral sobre pruebas.
En el siguiente ejemplo, se muestra una prueba de muestra para el componente creado:
import React from 'react';
import {
render,
screen,
getTranslation,
checkA11yViolations,
} from '@jutro/test';
import messages from './CustomInput.messages';
import { CustomInput } from './CustomInput';
describe('CustomInput', () => {
it('renders default component', () => {
const sampleTitle = 'sample';
render(<CustomInput title={sampleTitle} />);
expect(screen.getByTitle('sample')).toBeInTheDocument();
});
it('renders with custom prop value', () => {
const newTitle = 'newTitle';
render(<CustomInput title={newTitle} />);
expect(screen.getByTitle(newTitle)).toBeInTheDocument();
});
it('renders with css class', () => {
const sampleTitle = 'sample';
render(<CustomInput title={sampleTitle} />);
expect(screen.getByTitle('sample')).toHaveClass('customInput');
});
it('renders with translation', () => {
render(<CustomInput />);
expect(
screen.getByText(getTranslation(messages.label))
).toBeInTheDocument();
});
it('has no a11y violations', async () => {
await checkA11yViolations(<CustomInput />);
});
});
Componentes en un nuevo paquete
A la hora de crear componentes que deben ser totalmente autónomos y reutilizables, se recomienda crear un árbol de dependencias en un archivo package.json al nivel del componente. A continuación, creará un archivo JavaScript que será el punto de entrada de su módulo que importe todos los subcomponentes y los exporte de nuevo para que puedan reutilizarse.
Para un componente llamado MyCustomComponent:
-
Creará una nueva carpeta llamada
CustomInput -
Creará
index.jspara exportar subcomponentes deCustomComponent, así:import SubComponent1 from './SubComponent1';
import SubComponent2 from './SubComponent2';
import SubComponent3 from './SubComponent3';
export { SubComponent1, SubComponent2, SubComponent3 }; -
Definirá el archivo
package.jsoncon dependencias.{
"name": "my-custom-component-module",
"description": "Description for my-component",
"main": "index.js",
"version": "1.0.1-32745cd39da0",
"author": "Your Name",
"private": true,
"dependencies": {
// other component modules are re-used by MyComponent
"self-contained-component-module": "someVersion",
"another-self-contained-component-module": "someVersion"
},
"peerDependencies": {
// dependencies such as React, Lodash are set as peer dependencies
"react": "18.x",
"prop-types": "15.x",
"react-intl": "2.9.x",
"lodash": "4.x",
"classnames": "^2.x"
}
} -
Agregará la referencia del módulo (my-component-module) al
package.jsonde la aplicación como una dependencia. -
Usará el módulo importando desde el paquete.
import { SubComponent1, SubComponent3 } from 'my-custom-component-module';
Este componente y sus subcomponentes se pueden reutilizar libremente en la aplicación.