Saltar al contenido principal

Renderización con esquemas

Como se mencionó en la documentación del SDK de Digital, el beneficio de trabajar con esquemas es que proporcionan toda la información necesaria para crear dinámicamente una interfaz de usuario, siempre y cuando usted tenga los componentes correctos que comprendan estos esquemas.

En esta sección, aprenderá a renderizar automáticamente un esquema en una aplicación de React mediante el paquete @jutro/schema-adapter-components.

El paquete @jutro/schema-adapter-components es una biblioteca de componentes de React que sirve como puente entre algunos de los tipos de esquemas utilizados por el SDK de Digital y la biblioteca de componentes de Jutro.

Para poder utilizarlo, debe instalarlo en su proyecto:

npm install @jutro/schema-adapter-components

Una vez instalado, podrá utilizar los componentes Field y Term en su aplicación React.

Componentes del adaptador de esquema​

Los adaptadores Field y Term son componentes de React que aceptan un tipo específico de esquema y renderizan uno de los siguientes componentes de Jutro:

Note: Algunos de los componentes que renderiza el SDK de Digital han quedado obsoletos.

Si tiene componentes actualizados, utilice la siguiente importación:

import { Field, Term } from '@jutro/schema-adapter-components/new';

Si tiene componentes obsoletos, utilice la siguiente importación:

import { Field, Term } from '@jutro/schema-adapter-components/';

Lista de componentes obsoletos admitidos:

Para determinar qué componente de Jutro se va a renderizar, los componentes del adaptador utilizarán la información disponible en el esquema.

Field​

Puede utilizar el componente Field para renderizar un JSONSchemaField mediante la información del esquema con el componente de Jutro Design System más adecuado.

Propiedades del componente campo​

Nombre de la propiedadTipoDescripción
fieldsSchemaJSONSchemaWithFieldsEsquema principal de un JSONSchemaField. Tenga en cuenta que este no es el esquema del campo en sí, sino el del objeto que contiene el campo. Esto se debe a que parte de la información necesaria para renderizar el campo (como la obligatoriedad) solo está disponible en el esquema principal.
fieldNamestringNombre del campo que se va a renderizar. Debe ser un nombre de campo válido que exista en fieldsSchema.
devModebooleanEl valor predeterminado es false. Determina si el modo desarrollo está habilitado. Cuando el modo desarrollo está habilitado, se renderizará una advertencia en el campo si hay problemas para analizar el esquema o si no hay ningún componente asociado al esquema.
jutroComponentPropsobject o function
  • Si se pasa un objeto, sus propiedades se pasarán como propiedades para el componente de Jutro, lo que invalidará las propiedades calculadas por el adaptador.
  • Si se pasa una función, se la llamará mediante un objeto como argumento con las siguientes propiedades:
    • calculatedComponentName: nombre del componente de Jutro que se utilizará para renderizar el campo.
    • calculatedComponentProps: objeto con las propiedades calculadas predeterminadas que se pasarán al componente de Jutro.
    • schemaType: tipo de esquema, extraído del esquema del campo.
    Puede usar esta información para crear y devolver un objeto con las propiedades que desee transferir al componente de Jutro, lo que invalidará las propiedades calculadas por el adaptador.

Ejemplo de renderización de JSONSchemaField​

Tip: Para simplificar el ejemplo, usaremos una función ficticia que devuelve un objeto JSONSchemaWithFields, pero, en una aplicación real, deberá usar la función getSchema correspondiente.

Además, las funciones getSchema correspondientes pueden devolver esquemas que no tienen un tipo JSONSchemaWithFields, por eso, quizás sea necesario agregar un paso para convertir a JSONSchemaWithFields.

En este ejemplo, renderizaremos un campo firstName y lo asociaremos con el estado de React.

import { Field } from '@jutro/schema-adapter-components/new';

const getSchemaFields = (): JSONSchemaWithFields => {
// Dummy function returning a JSONSchemaWithFields object with a firstName property
// In a real application you will need to use the corresponding getSchema function
};

const MyComponent = () => {
const [firstNameValue, setFirstNameValue] = useState('');
const schemaWithFields = getSchemaFields();
const fieldName = 'firstName';

return (
<Field
key={fieldName}
fieldsSchema={schemaWithFields}
fieldName={fieldName}
jutroComponentProps={{
value: firstNameValue,
onValueChange: (_e, newValue) => {
setFirstNameValue(newValue);
},
}}
/>
);
};

Term​

Puede utilizar el componente Term para renderizar un JSONSchemaTerm mediante la información del esquema con el componente de Jutro Design System más adecuado.

Propiedades del componente término​

Nombre de la propiedadTipoDescripción
termsSchemaJSONSchemaWithTermsEsquema principal de un JSONSchemaTerm. Tenga en cuenta que este no es el esquema del término en sí, sino el del objeto que contiene el tema. Esto se debe a que parte de la información necesaria para renderizar el tema (como la obligatoriedad) solo está disponible en el esquema principal.
termNamestringNombre del término que se va a renderizar. Debe ser un nombre de término válido que exista en termsSchema.
devModebooleanEl valor predeterminado es false. Determina si el modo desarrollo está habilitado. Cuando el modo desarrollo está habilitado, se renderizará una advertencia en el término si hay problemas para analizar el esquema o si no hay ningún componente asociado al esquema.
jutroComponentPropsobject o function
  • Si se pasa un objeto, sus propiedades se pasarán como propiedades para el componente de Jutro, lo que invalidará las propiedades calculadas por el adaptador.
  • Si se pasa una función, se la llamará mediante un objeto como argumento con las siguientes propiedades:
    • calculatedComponentName: nombre del componente de Jutro que se utilizará para renderizar el término.
    • calculatedComponentProps: objeto con las propiedades calculadas predeterminadas que se pasarán al componente de Jutro.
    • schemaType: tipo de esquema, extraído del esquema del término.
    Puede usar esta información para crear y devolver un objeto con las propiedades que desee transferir al componente de Jutro, lo que invalidará las propiedades calculadas por el adaptador.

Ejemplo de renderización de JSONSchemaTerm​

Tip: Para simplificar el ejemplo, usaremos una función ficticia que devuelve un objeto JSONSchemaWithTerms, pero, en una aplicación real, deberá usar la función getSchema correspondiente.

En este ejemplo, renderizaremos un término excessValue y lo asociaremos con el estado de React.

import { Term } from '@jutro/schema-adapter-components/new';

const getSchemaTerms = (): JSONSchemaWithTerms => {
// Dummy function returning a JSONSchemaWithTerms object with a excessValue property
// In a real application you will need to use the corresponding getSchema function
};

const MyComponent = () => {
const [excessValue, setExcessValue] = useState(0);
const schemaWithTerms = getSchemaTerms();
const termName = 'excessValue';

return (
<Term
key={termName}
termsSchema={schemaWithTerms}
termName={termName}
jutroComponentProps={{
value: excessValue,
onValueChange: (_e, newValue) => {
setExcessValue(newValue);
},
}}
/>
);
};

Renderización automática de un esquema completo​

Uno de los casos de uso más útiles para el paquete @jutro/schema-adapter-components es la renderización automática de un esquema completo mediante un bucle a través de las propiedades de JSONSchemaWithFields o JSONSchemaWithTerms.

...

{Object.keys(schemaWithFields.properties).map((propertyName) => (
<Field
key={propertyName}
fieldsSchema={schemaWithFields}
fieldName={propertyName}
/>
))}

...

Sin embargo, dado que un adaptador Field o Term puede renderizar cualquiera de los componentes de Jutro enumerados anteriormente, y cada uno de estos componentes tiene su propio conjunto de propiedades, no siempre es posible pasar las mismas propiedades a todos los adaptadores dentro de un bucle.

Por ejemplo, DateField, DateTimeField, ToggleField utilizan la propiedad onValueChange, mientras que CurrencyInput, NumberInput, Select, TextArea y TextInput utilizan la propiedad onChange. Además, estos controladores onChange/onValueChange reciben diferentes argumentos desde los componentes.

Para gestionar esta inconsistencia, tendrá que escribir cierta lógica para determinar qué propiedades pasarán a cada componente de Jutro potencialmente renderizado. Puede escribir esta lógica utilizando la versión funcional de la propiedad jutroComponentProps existente en los componentes del adaptador Field y Term.

Example: Managing Jutro components inconsistent props
import { Field } from '@jutro/schema-adapter-components/new';

const getSchemaFields = (): JSONSchemaWithFields => {
// Dummy function returning a JSONSchemaWithFields object
// In a real application you will need to use the corresponding getSchema function
};

const MyComponent = () => {
const [values, setValues] = useState({});
const schemaWithFields = getSchemaFields();

return (
<div>
{Object.keys(schemaWithFields.properties).map((propertyName) => (
<Field
key={propertyName}
fieldsSchema={schemaWithFields}
fieldName={propertyName}
jutroComponentProps={({ calculatedComponentName }) => {
const onValueChangeComponents = [
'DateField',
'DateTimeField',
'ToggleField',
];

if (onValueChangeComponents.includes(calculatedComponentName)) {
return {
value: values[propertyName],
onValueChange: (newValue) => {
setValues((prevValues) => ({
...prevValues,
[propertyName]: newValue,
}));
},
};
}

return {
value: values[propertyName],
onChange: (_e, newValue) => {
setValues((prevValues) => ({
...prevValues,
[propertyName]: newValue,
}));
},
};
}}
/>
))}
</div>
);
};

Gestión de la transformación de datos​

Dado que los componentes del adaptador le permiten utilizar las propiedades del componente subyacente de Jutro, es posible que el formato de los valores que acepta el componente de Jutro sea diferente del formato de los valores en el esquema.

A modo de ejemplo, el componente adaptador de campo renderiza un componente NumberInput cuando:

  • el tipo de esquema es number;
  • el tipo de esquema es string y el esquema format es number.

Sin embargo, el componente NumberInput solo acepta un number como valor y solo pasará un number al controlador onChange como argumento. Esto significa que, en este caso, tendrá convertir el valor a un string antes de pasarlo como valor al NumberInput y otra vez a number antes de guardarlo en el estado de React, suponiendo que usará este estado de React directamente con las funciones del SDK getSchema y las funciones de la API.

Example: Casting to number when using NumberInput for strings

// This example assumes that you know in advance that the amount field's
// schema type is string and the schema format is number

<Field
key={"amount"}
fieldsSchema={schemaWithFields}
fieldName={"amount"}
jutroComponentProps={
value: Number.isNaN(Number(amountValue)) ? undefined : Number(amountValue)
onChange: (_e, newValue) => {
setAmountValue(Number.isNaN(newValue) ? undefined : newValue.toString());
},
}
/>

En caso de que esté renderizando dinámicamente un esquema completo dentro de un bucle, tendrá que escribir esta lógica utilizando la versión funcional de la propiedad jutroComponentProps como se explica en la sección anterior. Para ayudarlo a escribir todas estas condiciones, el tipo se extrae del esquema y se pasa a esta función, como la propiedad schemaType del objeto del argumento.

Personalización de la capa de presentación​

El paquete @jutro/schema-adapter-components es un buen punto de partida para renderizar esquemas en una aplicación de React mediante Jutro Design System, pero no es una solución adecuada para todos.

Note: Esta biblioteca es muy dogmática a la hora de decidir qué componente de Jutro es el más adecuado para un esquema determinado. Sin embargo, es posible que las decisiones prescritas no siempre coincidan con su caso de uso específico.

En esta sección, encontrará algunos casos de uso en los que podría necesitar una asignación diferente entre su esquema y los componentes de la interfaz de usuario, junto con algunas soluciones sugeridas.

Uso de un sistema de diseño diferente​

En caso de que no pueda utilizar Jutro Design System, deberá proporcionar su propia asignación entre la información existente en los esquemas y los componentes de su sistema de diseño.

Esto es necesario porque los diferentes sistemas de diseño tienen distintos componentes y propiedades, y no tiene sentido tratar de crear una biblioteca que se ajuste a todos ellos.

Una forma de proporcionar esta asignación a tipos comunes de esquema (como JSONSchemaField) es crear su propia versión de los componentes del adaptador (por ejemplo FieldSchemaMaterial).

Para ello, debe comprender la información disponible en el esquema y decidir cómo asignarla a los componentes del sistema de diseño. Encontrará más información sobre los diferentes tipos de esquemas en la página Tipos de esquemas.

Modificación del componente de Jutro​

No existe una forma sencilla de cambiar el componente de Jutro utilizado por la biblioteca @jutro/schema-adapter-components para renderizar un esquema determinado.

Esto se debe a que, aunque dos componentes de Jutro puedan tener algunas propiedades en común, en general, cada componente define su propio conjunto de propiedades.

Note: Invalidar el componente que se utiliza también requeriría redefinir la asignación a las propiedades del nuevo componente. Esto no sería más fácil que crear un nuevo componente de adaptador, que es el método recomendado en este caso.

En el siguiente ejemplo, crearemos un componente encapsulador alrededor del componente @jutro/schema-adapter-components Field, que utilizará un adaptador personalizado, en lugar de Field cuando el tipo de esquema sea booleano.

import { Field } from '@jutro/schema-adapter-components/new';

const FieldWithCustomBoolean = (props) => {
const { fieldsSchema, fieldName, ...rest } = props;

const fieldSchemaType = fieldsSchema.properties?.[fieldName]?.type;

if (fieldSchemaType === 'boolean') {
return <CustomBooleanAdapter {...props} />;
}

return <Field {...props} />;
};

Hay muchas formas diferentes de implementar el componente CustomBooleanAdapter. En cualquier caso, debe decidir cuál es la UX deseada y comprender la información disponible en el esquema antes de asignarlo a las propiedades de uno (o varios) componentes de Jutro.

Encontrará más información sobre los diferentes tipos de esquemas en la página Tipos de esquemas.

Renderización de errores de validación​

En la página Validación del esquema, se explica cómo se realiza la validación. En la sección Errores de validación, se detalla cómo las funciones de validación devuelven una lista de errores. La renderización de los errores requiere iterar esta lista y agregar los mensajes de error a la propiedad stateMessages del componente correspondiente.

En el siguiente ejemplo, se muestra una forma de renderizar estos errores. Este método de ejemplo consiste en crear manualmente una nueva función mapSchemaErrorsToFieldStateMessages que filtra los mensajes de error relevantes de la salida de la función de validación generada y devuelve una lista de strings de error necesaria para la propiedad stateMessages.


import { Field } from "@jutro/schema-adapter-components";
import { getAccountSchema } from "./generated/<your-sdk-name>/job";

const MyPage = () => {
const { schema, validate } = getAccountSchema();
const { errors } = validate();

return (
<div>
{Object.keys(schema.properties).map(propertyName) => (
<Field
key={propertyName}
fieldsSchema={schema}
fieldName={propertyName}
jutroComponentProps={{
value: ...,
onValueChange: ...,
stateMessages: mapSchemaErrorsToFieldStateMessages(errors, propertyName)
}}
/>
)}
</div>
)
}

const mapSchemaErrorsToFieldStateMessages = (validationErrors, fieldId) => {
const fieldErrors = validationErrors.filter(
error => error.instancePath === `/${fieldId}`
);

return {
error: fieldErrors.map(error => error.message),
};
}

Cómo ignorar los errores de validación​

En algunos casos, quizás sea conveniente ignorar los errores de validación. Por lo general, esto puede deberse a que el contenido quizás sea válido en su caso de uso.

Un caso de uso común es que el SDK siempre marcará un campo como obligatorio si está marcado como x-gw-requiredForQuote, independientemente del estado de flujo actual de su aplicación (por ejemplo, su aplicación puede estar en estado de creación de solicitud, en el que, en realidad, no se requiere un valor “obligatorio para cotizar”. Consulte la sección sobre palabras clave de validación para obtener más información).

En tales casos, debe ignorar el error de validación para evitar que bloquee el flujo de la aplicación. Si se sigue el método de renderización del ejemplo anterior, una forma de manejar el caso x-gw-requiredForQuote mencionado sería alterar la función personalizada mapSchemaErrorsToFieldStateMessages para excluir esos errores. El siguiente código es un ejemplo de cómo hacerlo:

const mapSchemaErrorsToFieldStateMessages = (
validationErrors,
fieldId,
ignoreFields
) => {
const fieldErrors = validationErrors.filter(
(error) => error.keyword !== 'x-gw-requiredForQuote'
);

return {
error: fieldErrors.map((error) => error.message),
};
};