
Este artículo será principalmente útil para desarrolladores que no trabajan con conjuntos de componentes ya preparados, como material-ui, pero implementan los suyos. Por ejemplo, se ha desarrollado un diseño para un producto que refleja cómo deberían ser los botones, las ventanas modales, etc. Para implementar correctamente dicho sistema de diseño, todos sus átomos necesitarán agregar un buen soporte para su composición. En otras palabras, es necesario garantizar que cualquier componente individual pueda integrarse y encajar perfectamente en un componente compuesto más grande. Y si no encaja, sería bueno tener un soporte simple para su personalización. Sea como fuere, este es un gran tema aparte, y tal vez volveré sobre él en otro momento.
Letras de canciones
Hola a todos Comienzo mi viaje en el centro con un artículo simple pero útil. En cuanto a mí, resultó demasiado detallado, pero aún así traté de adaptarme al lector, y no a mí mismo. Antes de escribir el siguiente artículo (si hay uno) sobre un tema más complejo, deseo ajustar mi presentación sobre los comentarios (si hay uno).
Términos utilizados:
- Un componente visual es un componente que devuelve un elemento incrustado en el DOM. Por ejemplo,
return (<div />)
. Un componente que devuelve solo otro componente no debe interpretarse visualmente.
Introduccion
Cuando desarrollas un componente, no puedes hacerlo completamente universal. En su mente, siempre comienza con opciones específicas para su uso. A menudo resulta que después del desarrollo, sus colegas comienzan a "empujar este componente a cualquier parte". Estás enojado con ellos: “¡Bueno, no lo desarrollé para esto! ¡No está destinado a esta tarea! ” Por supuesto, las mejoras son inevitables e incluso necesarias. Pero esto no debería ser mejoras como lanzar un nuevo accesorio para aumentar la sangría de 4px a 8px, que se utilizará en uno o dos casos de cada cincuenta. Los componentes deben tener geometría externa personalizada.
TypeScript, ayuda
Considere la interfaz, que en sentido debe ubicarse, por ejemplo, en
src/Library/Controls.ts
. Se dan breves comentarios para los campos, a continuación los analizaremos con más detalle.
export interface VisualComponentProps {
Esta es la interfaz de accesorios del componente. Cuales? Todos los componentes visuales. Deben aplicarse a su elemento raíz.
Los accesorios de cada componente visual desarrollado se deben ampliar utilizando esta interfaz.
Inmediatamente, preste atención al hecho de que todos estos accesorios son opcionales. Considéralos.
- los elementos secundarios están en los componentes de la clase React.Component, componentes del componente React.FC, pero no están en funciones normales sin especificar la tipificación React.FC. Por lo tanto, le preguntamos.
className/style
usamos nombres similares, como en el JSX'nom <div /> habitual. No producimos semántica. Este principio de identidad del nombre se usa, por ejemplo, en accesorios para especificar el enlace de referencia .doNotRender
usa como una alternativa a la muleta dolorosa en la renderización JSX por condición . Al aplicar esta solución, no necesitamos poner llaves en los métodos de renderizado, lo que perjudica la legibilidad del código. Compare 2 fragmentos de código:
Representación condicional virgen:
App.tsx
renderComponent() { const {props, state} = this; const needRender = state.something; return ( <PageLayout> <UIButton children={'This is a button'} /> {needRender && <UIButton children={'This is another button'} /> } </PageLayout> ); }
Accesorios de Chad noNotRender:
App.tsx
renderComponent() { const {props, state} = this; const needRender = state.something; return ( <PageLayout> <UIButton children={'This is a button'} /> <UIButton children={'This is another button'} doNotRender={!needRender} /> </PageLayout> ); }
En la primera versión, aumentamos el nivel de anidación del botón inferior, aunque en términos de significado, su anidación está en el mismo nivel que el superior. Se ve mal en mi editor, donde uso una pestaña con un ancho de 2 espacios, y aquí es aún peor.
En la segunda opción, tenemos un anidamiento igual, menos que doNotRender no atraiga la atención y el desarrollador no entienda lo que está sucediendo. Pero, si en su proyecto cada componente visual se realiza de acuerdo con este principio, entonces este problema desaparece de inmediato.
fallback
necesita un doNotRender true
si no queremos que sea null
con doNotRender true
, sino algún tipo de elemento personalizado. Se usa por analogía con React Suspense , ya que tiene un significado similar (no producimos semántica)
Quiero mostrar cómo usarlo correctamente. Hagamos un botón simple.
Nota: en el siguiente código también uso css-modules, sass y classnames.
UIButton.tsx
import * as React from 'react'; import { VisualComponentProps } from 'Library/Controls'; import * as css from './Button.sass'; import cn from 'classnames';
App.tsx
renderComponent() { const {props, state} = this; const needRenderSecond = true; return ( <PageLayout> <UIButton children={'This is a button'} style={{marginRight: needRenderSecond ? 5 : null}} /> <UIButton disabled children={'This is another button'} doNotRender={!needRenderSecond} /> </PageLayout> ); }
Resultado:

Reflexión y Conclusión
Es conveniente operar con componentes tales como divs, creando varios envoltorios, composiciones, especializaciones,
yendo más allá del marco de la funcionalidad original incrustada en ellos .
Se puede argumentar que, dado que no hay botones amarillos condicionales en el sistema de diseño, y el desarrollador necesita hacerlos, entonces el problema no está en los componentes, sino en el hecho de que esta necesidad crea. Sin embargo, la realidad es que tales situaciones surgen, y con bastante frecuencia. "... ¡Pero debemos vivir! Debemos vivir". Además, el principio de cascada css no siempre se puede implementar en la práctica, y puede experimentar casos en los que sus estilos simplemente se superponen con la mayor especificidad de otro selector (o descrito anteriormente). Aquí el estilo simplemente ayuda.
Finalmente, agregaré un par (literalmente) de momentos.
- Tenga en cuenta que doNotRender no repite completamente el comportamiento de representación condicional. También ejecutará métodos de ciclo de vida, solo render devolverá un retroceso o nulo. En algunos componentes complejos, es posible que desee evitar la ejecución de métodos de ciclo de vida. Para hacer esto, solo necesita hacer una especialización incorporada de su componente.
Usando el ejemplo de UIButton: cambie el nombre de UIButton a UIButtonInner y agregue el siguiente código debajo:
UIButton.tsx
export function UIButton(props: ButtonProps) { if (props.doNotRender) return props.fallback || null; return <UIButtonInner {...props} />; }
PD: ¡No cometas un error de llamada recursiva UIButton en esta función!
- En casos excepcionales cuando los estilos en el contenedor y en el componente envuelto pueden cambiar de forma independiente, la siguiente interfaz puede serle útil.
Library/Controls.ts
export interface VisualComponentWrapperProps extends VisualComponentProps { wrappedVisual?: VisualComponentProps; }
Y su usoUIButton.tsx
interface ButtonSomeWrapperProps extends ButtonBasicProps, VisualComponentWrapperProps { myCustomProp?: number; } export function UIButtonSomeWrapper(props: ButtonSomeWrapperProps) { if (props.doNotRender) return props.fallback || null; const {
El desarrollo de una aplicación que utilice este enfoque aumentará significativamente la reutilización de sus componentes, reducirá la cantidad de estilos de muletas innecesarios (hablando de los estilos descritos en los archivos de estilo del componente exclusivamente para las necesidades de otros componentes) y accesorios, y agregará código estructurado. Eso es todo En el próximo artículo, comenzaremos a resolver los problemas de reutilización de componentes más en términos de código que css. O escribiré sobre algo más interesante. Gracias por su atencion