Web MDC-112: Mengintegrasikan MDC dengan Framework Web

1. Pengantar

logo_components_color_2x_web_96dp.png

Komponen Material (MDC) membantu developer menerapkan Desain Material. Dibuat oleh tim engineer dan desainer UX di Google, MDC memiliki banyak komponen UI yang indah dan fungsional serta tersedia untuk Android, iOS, web, dan Flutter.material.io/develop

MDC Web direkayasa untuk diintegrasikan ke dalam framework frontend apa pun sambil menjunjung tinggi prinsip Desain Material. Codelab berikut memandu Anda membangun Komponen React, yang menggunakan MDC Web sebagai fondasi. Prinsip yang dipelajari dalam codelab ini dapat diterapkan ke framework JavaScript apa pun.

Cara MDC Web dibuat

Lapisan JavaScript MDC Web terdiri dari tiga class per komponen: Component, Foundation, dan Adapter. Pola ini memberi MDC Web fleksibilitas untuk berintegrasi dengan framework frontend.

Foundation berisi logika bisnis yang menerapkan Desain Material. Foundation tidak mereferensikan elemen HTML apa pun. Hal ini memungkinkan kita mengabstraksi logika interaksi HTML ke dalam Adapter. Foundation memiliki Adapter.

Adapter adalah antarmuka. Antarmuka Adapter direferensikan oleh Foundation untuk menerapkan logika bisnis Desain Material. Anda dapat menerapkan Adapter dalam berbagai framework seperti Angular atau React. Implementasi Adapter berinteraksi dengan struktur DOM.

Component memiliki Foundation, dan perannya adalah

  1. Mengimplementasikan Adapter, menggunakan JavaScript non-framework, dan
  2. Menyediakan metode publik yang melakukan proxy ke metode di Foundation.

Yang disediakan MDC Web

Setiap paket di MDC Web dilengkapi dengan Component, Foundation, dan Adapter. Untuk membuat instance Komponen , Anda harus meneruskan elemen root ke metode konstruktor Komponen. Component mengimplementasikan Adapter, yang berinteraksi dengan elemen DOM dan HTML. Component kemudian membuat instance Foundation, yang memanggil metode Adapter.

Untuk mengintegrasikan MDC Web ke dalam framework, Anda harus membuat Component sendiri dalam bahasa/sintaksis framework tersebut. Component framework mengimplementasikan Adapter MDC Web dan menggunakan Foundation MDC Web.

Yang akan Anda bangun

Codelab ini menunjukkan cara membangun Adapter kustom untuk menggunakan logika Foundation guna mencapai Komponen React Desain Material. Codelab ini mencakup topik lanjutan yang ditemukan di Mengintegrasikan ke dalam Framework. React digunakan dalam codelab ini sebagai contoh framework, tetapi pendekatan ini dapat diterapkan ke framework lain.

Dalam codelab ini, Anda akan membangun Panel Aplikasi Atas dan membuat ulang halaman demo panel aplikasi atas demo page. Tata letak halaman demo sudah disiapkan sehingga Anda dapat mulai mengerjakan Panel Aplikasi Atas. Panel Aplikasi Atas akan mencakup:

  • Ikon navigasi
  • Item tindakan
  • Ada 4 varian yang tersedia: varian Short, always collapsed, fixed, dan prominent

Yang Anda perlukan:

  • Node.js
  • Kode contoh (yang akan didownload pada langkah berikutnya)
  • Pengetahuan dasar tentang HTML, CSS, JavaScript, dan React

Sejauh mana pengalaman Anda dalam pengembangan web?

Pemula Menengah Mahir

2. Menyiapkan lingkungan pengembangan

Mendownload aplikasi codelab awal

Aplikasi awal terletak di direktori material-components-web-codelabs-master/mdc-112/starter.

...atau meng-clone codelab dari GitHub

Untuk meng-clone codelab ini dari GitHub, jalankan perintah berikut:

git clone https://github.com/material-components/material-components-web-codelabs
cd material-components-web-codelabs/mdc-112/starter

Menginstal dependensi project

Dari direktori awal material-components-web-codelabs/mdc-112/starter, jalankan:

npm install

Anda akan melihat banyak aktivitas dan pada akhirnya, terminal Anda akan menampilkan penginstalan yang berhasil:

22a33efc2a687408.png

Menjalankan aplikasi awal

Di direktori yang sama, jalankan:

npm start

webpack-dev-server akan dimulai. Arahkan browser Anda ke http://localhost:8080/ untuk melihat halaman.

b55c66dd400cf34f.png

Berhasil! Kode awal untuk halaman Demo React Panel Aplikasi Atas akan berjalan di browser Anda. Anda akan melihat dinding teks lorem ipsum, kotak Controls (kanan bawah), dan Panel Aplikasi Atas yang belum selesai:

4ca3cf6d216f9290.png

Melihat kode dan project

Jika Anda membuka editor kode, direktori project akan terlihat seperti:

e9a3270d6a67c589.png

Buka file App.js dan lihat metode render, yang menyertakan Komponen <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>
    );
  }

Ini adalah titik entri untuk TopAppBar di aplikasi.

Buka file TopAppBar.js yang merupakan class Component React kosong dengan metode render:

TopAppBar.js

import React from 'react';

export default class TopAppBar extends React.Component {
  render() {
    return (
      <header>
        TOP APP BAR
      </header>
    );
  }
}

3. Komposisi komponen

Di React, metode render menampilkan HTML Komponen. Komponen Panel Aplikasi Atas akan merender tag <header />, dan akan terdiri dari 2 bagian utama:

  1. Bagian ikon dan judul navigasi
  2. Bagian ikon tindakan

Jika Anda memiliki pertanyaan tentang elemen yang membentuk Panel Aplikasi Atas, buka dokumentasi di GitHub.

Ubah metode render() di TopAppBar.js agar terlihat seperti ini:

  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>
    );
  }

Ada dua elemen bagian dalam HTML ini. Yang pertama berisi ikon dan judul navigasi. Yang kedua berisi ikon tindakan.

Selanjutnya, tambahkan metode 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>
  );
}

Developer akan mengimpor TopAppBar ke dalam aplikasi React dan meneruskan ikon tindakan ke elemen TopAppBar. Anda dapat melihat kode contoh yang menginisialisasi TopAppBar di App.js.

Metode getMergedStyles tidak ada, yang digunakan dalam metode render. Tambahkan metode JavaScript berikut ke class TopAppBar:

getMergedStyles = () => {
  const {style} = this.props;
  const {style: internalStyle} = this.state;
  return Object.assign({}, internalStyle, style);
}

this.classes juga tidak ada dalam metode render, tetapi akan dibahas di bagian selanjutnya. Selain metode getter yang tidak ada, this.classes, masih ada bagian TopAppBar yang perlu Anda implementasikan sebelum Panel Aplikasi Atas dapat dirender dengan benar.

Bagian Komponen React yang masih tidak ada di Panel Aplikasi Atas adalah:

  • Fondasi yang diinisialisasi
  • Metode adaptor untuk diteruskan ke fondasi
  • Markup JSX
  • Pengelolaan varian (tetap, pendek, selalu diciutkan, menonjol)

Pendekatan

  1. Implementasikan metode Adapter.
  2. Lakukan inisialisasi Foundation di componentDidMount.
  3. Panggil metode Foundation.destroy di componentWillUnmount.
  4. Tetapkan pengelolaan varian melalui metode getter yang menggabungkan nama class yang sesuai.

4. Mengimplementasikan metode Adapter

Component TopAppBar JS non-framework mengimplementasikan metode Adapter berikut (yang tercantum secara mendetail di sini):

  • hasClass()
  • addClass()
  • removeClass()
  • registerNavigationIconInteractionHandler()
  • deregisterNavigationIconInteractionHandler()
  • notifyNavigationIconClicked()
  • setStyle()
  • getTopAppBarHeight()
  • registerScrollHandler()
  • deregisterScrollHandler()
  • registerResizeHandler()
  • deregisterResizeHandler()
  • getViewportScrollY()
  • getTotalActionItems()

Karena React memiliki peristiwa sintetis dan praktik serta pola coding terbaik yang berbeda, metode Adapter perlu diimplementasikan ulang.

Metode Getter Adaptor

Di file TopAppBar.js, tambahkan metode JavaScript berikut ke 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,
  };
}

API adaptor untuk pendaftaran peristiwa scroll dan ubah ukuran diimplementasikan secara identik dengan versi JS non-framework, karena React tidak memiliki peristiwa sintetis untuk scrolling atau mengubah ukuran dan menunda ke sistem peristiwa DOM native. getViewPortScrollY juga harus ditunda ke DOM native karena merupakan fungsi pada objek window, yang tidak ada di API React. Implementasi adaptor akan berbeda untuk setiap framework.

Anda mungkin melihat this.setStyle tidak ada, yang dipanggil oleh metode get adapter. Di file TopAppBar.js, tambahkan metode JavaScript yang tidak ada ke class TopAppBar:

setStyle = (varName, value) => {
  const updatedStyle = Object.assign({}, this.state.style);
  updatedStyle[varName] = value;
  this.setState({style: updatedStyle});
}

Anda baru saja mengimplementasikan Adapter. Perhatikan bahwa Anda mungkin melihat error di konsol pada tahap ini karena implementasi lengkap belum selesai. Bagian berikutnya akan memandu Anda cara menambahkan dan menghapus class CSS.

5. Mengimplementasikan metode Komponen

Mengelola Varian dan Class

React tidak memiliki API untuk mengelola class. Untuk meniru metode class CSS tambah/hapus JavaScript native, tambahkan variabel status classList. Ada tiga bagian kode di TopAppBar yang berinteraksi dengan class CSS:

  1. Komponen <TopAppBar /> melalui properti className.
  2. Metode Adapter melalui addClass atau removeClass.
  3. Dikodekan secara hardcode dalam Komponen React <TopAppBar />.

Pertama, tambahkan impor berikut di bagian atas TopAppBar.js, di bawah impor yang ada:

import classnames from 'classnames';

Kemudian, tambahkan kode berikut di dalam deklarasi class Komponen 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,
    });
  }

  ... 
}

Jika Anda membuka http://localhost:8080, kotak centang Kontrol kini akan mengaktifkan/menonaktifkan nama class dari DOM.

Kode ini membuat TopAppBar dapat digunakan oleh banyak developer. Developer dapat berinteraksi dengan TopAppBar API, tanpa perlu khawatir tentang detail implementasi class CSS.

Anda kini telah berhasil mengimplementasikan Adapter. Bagian berikutnya akan memandu Anda membuat instance Foundation.

Memasang dan Melepas Komponen

Pembuatan instance Foundation terjadi dalam metode componentDidMount.

Pertama, impor fondasi Panel Aplikasi Atas MDC dengan menambahkan impor berikut setelah impor yang ada di TopAppBar.js:

import {MDCTopAppBarFoundation, MDCFixedTopAppBarFoundation, MDCShortTopAppBarFoundation} from '@material/top-app-bar';

Selanjutnya, tambahkan kode JavaScript berikut ke dalam class 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();
  }
 
  ... 

}

Salah satu praktik coding React yang baik adalah menentukan propTypes dan defaultProps. Tambahkan impor berikut setelah impor yang ada di TopAppBar.js:

import PropTypes from 'prop-types';

Kemudian, tambahkan kode berikut ke bagian bawah TopAppBar.js (setelah class Komponen):

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,
};

Anda kini telah berhasil mengimplementasikan Komponen React Panel Aplikasi Atas. Jika membuka http://localhost:8080, Anda dapat menggunakan halaman demo. Halaman demo akan berfungsi sama dengan halaman demo MDC Web. Halaman demo akan terlihat seperti ini:

3d983b98c2092e7a.png

6. Rangkuman

Dalam tutorial ini, kita membahas cara menggabungkan Foundation MDC Web untuk digunakan dalam aplikasi React. Ada beberapa library di GitHub dan npm yang menggabungkan Komponen MDC Web seperti yang dijelaskan dalam Mengintegrasikan ke dalam Framework. Sebaiknya gunakan daftar yang ditemukan di sini. Daftar ini juga mencakup framework lain selain React seperti Angular dan Vue.

Tutorial ini menyoroti keputusan kami untuk membagi kode MDC Web menjadi 3 bagian, yaitu Foundation, Adapter, dan Component. Arsitektur ini memungkinkan komponen berbagi kode umum saat bekerja dengan semua framework. Terima kasih telah mencoba Komponen Material React dan lihat library baru kami MDC React. Kami harap Anda menikmati codelab ini.

Saya dapat menyelesaikan codelab ini dengan upaya dan dalam durasi waktu yang wajar

Sangat setuju Setuju Netral Tidak setuju Sangat tidak setuju

Saya ingin terus menggunakan Komponen Material pada masa mendatang

Sangat setuju Setuju Netral Tidak setuju Sangat tidak setuju