1. Introducción
Los componentes de Material (MDC) ayudan a los desarrolladores a implementar Material Design. MDC, creado por un equipo de ingenieros y diseñadores de UX en Google, cuenta con decenas de componentes de IU atractivos y funcionales, y está disponible para Android, iOS, la Web y Flutter.material.io/develop. |
MDC Web está diseñado para integrarse en cualquier framework de frontend y, al mismo tiempo, respetar los principios de Material Design. En el siguiente codelab, se te guiará para crear un componente de React, que usa MDC Web como base. Los principios que aprendiste en este codelab se pueden aplicar a cualquier framework de JavaScript.
Cómo se crea MDC Web
La capa de JavaScript de MDC Web consta de tres clases por componente: Component, Foundation y Adapter. Este patrón le brinda a MDC Web la flexibilidad para integrarse con los frameworks de frontend.
Foundation contiene la lógica empresarial que implementa Material Design. La Fundación no hace referencia a ningún elemento HTML. Esto nos permite abstraer la lógica de interacción de HTML en Adapter. Foundation tiene un adaptador.
El adaptador es una interfaz. Foundation hace referencia a la interfaz de Adapter para implementar la lógica empresarial de Material Design. Puedes implementar el adaptador en diferentes frameworks, como Angular o React. Una implementación de un adaptador interactúa con la estructura del DOM.
El Componente tiene una Fundación y su función es
- Implementa el adaptador con JavaScript que no sea de framework.
- Proporciona métodos públicos que actúen como proxy para métodos en Foundation.
Qué proporciona MDC Web
Cada paquete de MDC Web incluye un componente, un fundamento y un adaptador. Para crear una instancia de un Componente, debes pasar el elemento raíz al método del constructor del componente. El Component implementa un Adapter, que interactúa con los elementos DOM y HTML. Luego, el Componente crea una instancia de Foundation, que llama a los métodos de Adapter.
Para integrar MDC Web en un framework, debes crear tu propio componente en el lenguaje o la sintaxis de ese framework. El componente del framework implementa el adaptador de MDC Web y usa Foundation de MDC Web.
Qué compilarás
En este codelab, se muestra cómo compilar un Adapter personalizado para usar la lógica Foundation y lograr un componente de React de Material Design. En él, se abordan los temas avanzados que se encuentran en Integración en frameworks. En este codelab, React se usa como un framework de ejemplo, pero este enfoque se puede aplicar a cualquier otro framework.
En este codelab, compilarás la barra superior de la app y recrearás la página de demostración de la barra superior de la app. El diseño de la página de demostración ya está configurado para que puedas comenzar a trabajar en la barra superior de la aplicación. La barra superior de la aplicación incluirá lo siguiente:
- Ícono de navegación
- Elementos de acción
- Hay 4 variantes disponibles: corta, siempre contraída, fija y prominente.
Requisitos:
- Una versión reciente de Node.js (que se incluye con npm, un administrador de paquetes de JavaScript)
- El código de muestra (que se descargará en el siguiente paso)
- Conocimientos básicos de HTML, CSS, JavaScript y React
¿Cómo calificarías tu nivel de experiencia con el desarrollo web?
2. Configura el entorno para desarrolladores
Descarga la app de inicio del codelab
La app de partida se encuentra en el directorio material-components-web-codelabs-master/mdc-112/starter
.
… o clónalo desde GitHub
Para clonar este codelab desde GitHub, ejecuta los siguientes comandos:
git clone https://github.com/material-components/material-components-web-codelabs
cd material-components-web-codelabs/mdc-112/starter
Instala las dependencias del proyecto
Desde el directorio de partida material-components-web-codelabs/mdc-112/starter
, ejecuta lo siguiente:
npm install
Verás mucha actividad y, al final, la terminal debería mostrar una instalación correcta:
Cómo ejecutar la app de inicio
En el mismo directorio, ejecuta lo siguiente:
npm start
Se iniciará el webpack-dev-server
. Dirige tu navegador a http://localhost:8080/ para ver la página.
¡Listo! El código de partida para la página de demostración de React de la barra superior de la app debería estar ejecutándose en tu navegador. Deberías ver un muro de texto lorem ipsum, un cuadro Controls (en la parte inferior derecha) y una barra superior de la app sin terminar:
Mira el código y el proyecto
Si abres el editor de código, el directorio del proyecto debería verse de la siguiente manera:
Abre el archivo App.js
y observa el método render
, que incluye el componente <TopAppBar>
:
App.js
render() {
const {isFixed, isShort, isRtl, isProminent, isAlwaysCollapsed, shouldReinit} = this.state;
return (
<section
dir={isRtl ? 'rtl' : 'ltr'}
className='mdc-typography'>
{
shouldReinit ? null :
<TopAppBar
navIcon={this.renderNavIcon()}
short={isShort}
prominent={isProminent}
fixed={isFixed}
alwaysCollapsed={isAlwaysCollapsed}
title='Mountain View, CA'
actionItems={this.actionItems}
/>
}
<div className={classnames('mdc-top-app-bar--fixed-adjust', {
'mdc-top-app-bar--short-fixed-adjust': isShort || isAlwaysCollapsed,
'mdc-top-app-bar--prominent-fixed-adjust': isProminent,
})}>
{this.renderDemoParagraphs()}
</div>
{this.renderControls()}
</section>
);
}
Este es el punto de entrada para TopAppBar
en la aplicación.
Abre el archivo TopAppBar.js
, que es una clase Component
de React sin procesar con un método render
:
TopAppBar.js
import React from 'react';
export default class TopAppBar extends React.Component {
render() {
return (
<header>
TOP APP BAR
</header>
);
}
}
3. Composición del componente
En React, el método render
genera el código HTML del componente. El componente de la barra superior de la aplicación renderizará una etiqueta <header />
y se compondrá de 2 secciones principales:
- Ícono de navegación y sección del título
- Sección de íconos de acción
Si tienes preguntas sobre los elementos que componen la barra superior de la app, consulta la documentación en GitHub.
Modifica el método render()
en TopAppBar.js
para que se vea de la siguiente manera:
render() {
const {
title,
navIcon,
} = this.props;
return (
<header
className={this.classes}
style={this.getMergedStyles()}
ref={this.topAppBarElement}
>
<div className='mdc-top-app-bar__row'>
<section className='mdc-top-app-bar__section mdc-top-app-bar__section--align-start'>
{navIcon ? navIcon : null}
<span className="mdc-top-app-bar__title">
{title}
</span>
</section>
{this.renderActionItems()}
</div>
</header>
);
}
Hay dos elementos de sección en este código HTML. El primero contiene un ícono de navegación y un título. El segundo contiene íconos de acción.
Luego, agrega el método renderActionItems
:
renderActionItems() {
const {actionItems} = this.props;
if (!actionItems) {
return;
}
return (
<section className='mdc-top-app-bar__section mdc-top-app-bar__section--align-end' role='toolbar'>
{/* need to clone element to set key */}
{actionItems.map((item, key) => React.cloneElement(item, {key}))}
</section>
);
}
Un desarrollador importará TopAppBar
a su aplicación de React y pasará íconos de acción al elemento TopAppBar
. Puedes ver el código de ejemplo que inicializa un TopAppBar
en App.js
.
Falta el método getMergedStyles
, que se usa en el método render
. Agrega el siguiente método de JavaScript a la clase TopAppBar
:
getMergedStyles = () => {
const {style} = this.props;
const {style: internalStyle} = this.state;
return Object.assign({}, internalStyle, style);
}
this.classes
también falta en el método render
, pero se analizará en una sección posterior. Además del método get faltante, this.classes
, aún hay partes de TopAppBar
que debes implementar para que la barra superior de la app se renderice correctamente.
Las partes del componente de React que aún faltan en la barra superior de la app son las siguientes:
- Una base inicializada
- Métodos de adaptador para pasar a la base
- Lenguaje de marcado JSX
- Administración de variantes (fija, corta, siempre contraída, destacada)
El enfoque
- Implementa los métodos Adapter.
- Inicializa Foundation en
componentDidMount
. - Llama al método Foundation.destroy en
componentWillUnmount
. - Establece la administración de variantes a través de un método get que combina nombres de clases apropiados.
4. Implementa métodos de adaptador
El componente de JS TopAppBar
que no es un framework implementa los siguientes métodos de Adapter (que se indican en detalle aquí):
hasClass()
addClass()
removeClass()
registerNavigationIconInteractionHandler()
deregisterNavigationIconInteractionHandler()
notifyNavigationIconClicked()
setStyle()
getTopAppBarHeight()
registerScrollHandler()
deregisterScrollHandler()
registerResizeHandler()
deregisterResizeHandler()
getViewportScrollY()
getTotalActionItems()
Debido a que React tiene eventos sintéticos y diferentes prácticas recomendadas y patrones de codificación, los métodos Adapter deben volver a implementarse.
Método get del adaptador
En el archivo TopAppBar.js
, agrega el siguiente método de JavaScript a TopAppBar
:
get adapter() {
const {actionItems} = this.props;
return {
hasClass: (className) => this.classes.split(' ').includes(className),
addClass: (className) => this.setState({classList: this.state.classList.add(className)}),
removeClass: (className) => {
const {classList} = this.state;
classList.delete(className);
this.setState({classList});
},
setStyle: this.setStyle,
getTopAppBarHeight: () => this.topAppBarElement.current.clientHeight,
registerScrollHandler: (handler) => window.addEventListener('scroll', handler),
deregisterScrollHandler: (handler) => window.removeEventListener('scroll', handler),
registerResizeHandler: (handler) => window.addEventListener('resize', handler),
deregisterResizeHandler: (handler) => window.removeEventListener('resize', handler),
getViewportScrollY: () => window.pageYOffset,
getTotalActionItems: () => actionItems && actionItems.length,
};
}
Las APIs del adaptador para el registro de eventos de desplazamiento y cambio de tamaño se implementan de la misma manera que la versión de JS sin framework, ya que React no tiene ningún evento sintético para desplazarse o cambiar de tamaño, y aplaza el sistema de eventos de DOM nativo. getViewPortScrollY
también debe diferir al DOM nativo, ya que es una función en el objeto window
, que no está en la API de React. Las implementaciones del adaptador serán diferentes para cada framework.
Es posible que notes que falta this.setStyle
, al que llama el método get adapter
. En el archivo TopAppBar.js
, agrega el método de JavaScript faltante a la clase TopAppBar
:
setStyle = (varName, value) => {
const updatedStyle = Object.assign({}, this.state.style);
updatedStyle[varName] = value;
this.setState({style: updatedStyle});
}
Acabas de implementar Adapter. Ten en cuenta que es posible que veas errores en la consola en este momento porque la implementación completa aún no está completa. En la siguiente sección, se te guiará para agregar y quitar clases de CSS.
5. Implementa métodos de componentes
Administra variantes y clases
React no tiene una API para administrar clases. Para imitar los métodos de agregar o quitar clases de CSS de JavaScript nativo, agrega la variable de estado classList
. Hay tres fragmentos de código en TopAppBar
que interactúan con las clases de CSS:
- componente
<TopAppBar />
a través de la propiedadclassName
- El método Adapter a través de
addClass
oremoveClass
- Está codificado de forma fija en el componente React
<TopAppBar />
.
Primero, agrega la siguiente importación en la parte superior de TopAppBar.js
, debajo de las importaciones existentes:
import classnames from 'classnames';
Luego, agrega el siguiente código dentro de la declaración de clase del componente TopAppBar
:
export default class TopAppBar extends React.Component {
constructor(props) {
super(props);
this.topAppBarElement = React.createRef();
}
state = {
classList: new Set(),
style: {},
};
get classes() {
const {classList} = this.state;
const {
alwaysCollapsed,
className,
short,
fixed,
prominent,
} = this.props;
return classnames('mdc-top-app-bar', Array.from(classList), className, {
'mdc-top-app-bar--fixed': fixed,
'mdc-top-app-bar--short': short,
'mdc-top-app-bar--short-collapsed': alwaysCollapsed,
'mdc-top-app-bar--prominent': prominent,
});
}
...
}
Si vas a http://localhost:8080, las casillas de verificación de Control ahora deberían activar o desactivar los nombres de clase del DOM.
Este código permite que muchos desarrolladores puedan usar TopAppBar
. Los desarrolladores pueden interactuar con la API de TopAppBar
sin preocuparse por los detalles de implementación de las clases de CSS.
Ya implementaste correctamente el adaptador. En la siguiente sección, se te guiará para crear una instancia de Foundation.
Activa y desactiva el componente
La creación de instancias Foundation ocurre en el método componentDidMount
.
Primero, importa las bases de la barra superior de la app de MDC. Para ello, agrega la siguiente importación después de las importaciones existentes en TopAppBar.js
:
import {MDCTopAppBarFoundation, MDCFixedTopAppBarFoundation, MDCShortTopAppBarFoundation} from '@material/top-app-bar';
Luego, agrega el siguiente código JavaScript a la clase TopAppBar
:
export default class TopAppBar extends React.Component {
...
foundation_ = null;
componentDidMount() {
this.initializeFoundation();
}
componentWillUnmount() {
this.foundation_.destroy();
}
initializeFoundation = () => {
if (this.props.short) {
this.foundation_ = new MDCShortTopAppBarFoundation(this.adapter);
} else if (this.props.fixed) {
this.foundation_ = new MDCFixedTopAppBarFoundation(this.adapter);
} else {
this.foundation_ = new MDCTopAppBarFoundation(this.adapter);
}
this.foundation_.init();
}
...
}
Una buena práctica de codificación de React es definir propTypes y defaultProps. Agrega la siguiente importación después de las importaciones existentes en TopAppBar.js:
import PropTypes from 'prop-types';
Luego, agrega el siguiente código al final de TopAppBar.js
(después de la clase Component):
import PropTypes from 'prop-types';
TopAppBar.propTypes = {
alwaysCollapsed: PropTypes.bool,
short: PropTypes.bool,
fixed: PropTypes.bool,
prominent: PropTypes.bool,
title: PropTypes.string,
actionItems: PropTypes.arrayOf(PropTypes.element),
navIcon: PropTypes.element,
};
TopAppBar.defaultProps = {
alwaysCollapsed: false,
short: false,
fixed: false,
prominent: false,
title: '',
actionItems: null,
navIcon: null,
};
Ya implementaste con éxito el componente de React de la barra superior de la app. Si navegas a http://localhost:8080, puedes jugar con la página de demostración. La página de demostración funcionará de la misma manera que la página de demostración de MDC Web. La página de demostración debería verse de la siguiente manera:
6. Conclusión
En este instructivo, explicamos cómo unir Foundation de MDC Web para usarlo en una aplicación de React. Hay algunas bibliotecas en GitHub y npm que unen los componentes web de MDC como se describe en Integración en frameworks. Te recomendamos que uses la lista que se encuentra aquí. Esta lista también incluye otros frameworks además de React, como Angular y Vue.
En este instructivo, se destaca nuestra decisión de dividir el código web de MDC en 3 partes: Foundation, Adapter y Component. Esta arquitectura permite que los componentes compartan código común mientras trabajan con todos los frameworks. Gracias por probar Material Components React. Consulta nuestra nueva biblioteca MDC React. Esperamos que hayas disfrutado de este codelab.