One place for hosting & domains

      dengan

      Cara Memulai Ulang Aplikasi Node.js secara Otomatis dengan nodemon


      Pengantar

      Dalam Node.js, Anda perlu memulai ulang proses untuk menerapkan perubahan. Ini menambah langkah ekstra ke alur kerja Anda demi menerapkan perubahan. Anda dapat menghilangkan langkah ekstra ini dengan nodemon untuk memulai ulang prosesnya secara otomatis.

      nodemon adalah antarmuka baris-perintah (CLI) yang dikembangkan oleh @rem yang mengemas aplikasi Node Anda, memantau sistem berkas, dan secara otomatis memulai ulang proses.

      Dalam artikel ini, Anda akan mempelajari tentang menginstal, menyiapkan, dan mengonfigurasi nodemon.

      Prasyarat

      Jika Anda ingin mengikuti artikel ini, Anda membutuhkan:

      Langkah 1 — Menginstal nodemon

      Pertama, Anda perlu menginstal nodemon di mesin Anda. Instal utilitas secara global maupun secara lokal pada proyek Anda menggunakan npm atau Yarn:

      Instalasi Global

      Anda dapat menginstal nodemon secara global dengan npm:

      Atau dengan Yarn:

      Instalasi Lokal

      Anda juga dapat menginstal nodemon secara lokal dengan npm. Ketika melakukan instalasi lokal, kita dapat menginstal nodemon sebagai dependensi dev dengan --save-dev (atau --dev):

      • npm install nodemon --save-dev

      Atau dengan Yarn:

      Satu hal yang harus disadari dengan instalasi lokal adalah Anda tidak akan dapat menggunakan perintah nodemon secara langsung dari baris perintah:

      Output

      • command not found: nodemon

      Namun, Anda dapat menggunakannya sebagai bagian dari skrip npm atau dengan npx.

      Ini adalah akhir dari proses instalasi nodemon. Selanjutnya, kita akan menggunakan nodemon dengan proyek kita.

      Langkah 2 — Menyiapkan Proyek Express Contoh dengan nodemon

      Kita dapat menggunakan nodemon untuk memulai skrip Node. Misalnya, jika kita memiliki penyiapan server Express di dalam berkas server.js, kita dapat memulainya dan memantau perubahan seperti ini:

      Anda dapat memasukkan argumen dengan cara yang sama seperti Anda menjalankan skrip dengan Node:

      Setiap kali Anda membuat perubahan terhadap berkas dengan salah satu dari ekstensi asali yang dipantau (.js, .mjs, .json, .coffee, atau .litcoffee) di dalam direktori atau subdirektori saat ini, proses akan memulai ulang.

      Mari kita asumsikan kita menulis suatu berkas contoh server.js yang mengeluarkan pesan: Dolphin app listening on port ${port}!.

      Kita dapat menjalankan contoh dengan nodemon:

      Kita akan melihat keluaran terminal berikut:

      Output

      [nodemon] 1.17.3 [nodemon] to restart at any time, enter `rs` [nodemon] watching: *.* [nodemon] starting `node server.js` Dolphin app listening on port 3000!

      Sementara nodemon masih berjalan, mari kita buat perubahan terhadap berkas server.js untuk mengeluarkan pesan: Shark app listening on port ${port}!.

      Kita akan melihat keluaran terminal tambahan berikut:

      Output

      [nodemon] restarting due to changes... [nodemon] starting `node server.js` Shark app listening on port 3000!

      Keluaran terminal dari aplikasi Node.js akan menampilkan seperti yang diharapkan. Anda dapat memulai ulang prosesnya kapan pun dengan mengetik rs dan menekan ENTER.

      Sebagai alternatif, nodemon juga akan mencari berkas main yang ditentukan dalam berkas package.json dari proyek Anda:

      package.json

      {
        // ...
        "main": "server.js",
        // ...
      }
      

      Atau, skrip start:

      package.json

      {
        // ...
        "scripts": {
          "start": "node server.js"
        },
        // ...
      }
      

      Setelah Anda membuat perubahan pada package.json, Anda kemudian dapat memanggil nodemon untuk memulai aplikasi contoh di mode pemantauan tanpa harus memasukkan server.js.

      Langkah 3 — Menggunakan Opsi

      Anda dapat memodifikasi pengaturan konfigurasi yang tersedia untuk nodemon.

      Mari kita bahas beberapa opsi utama:

      • --exec: Pakai switch --exec guna menentukan biner untuk mengeksekusi berkas. Misalnya, saat dikombinasikan dengan biner ts-node, --exec dapat menjadi berguna untuk memantau perubahan dan menjalankan berkas TypeScript.
      • --ext: Menentukan ekstensi berkas berbeda yang harus dipantau. Untuk switch ini, berikan daftar ekstensi berkas yang harus dipisahkan oleh koma (misalnya, --ext js,ts).
      • --delay: Secara asali, nodemon menunggu selama satu detik untuk memulai ulang proses saat berkas berubah, tetapi dengan switch --delay, Anda dapat menentukan waktu tunggu yang berbeda. Misalnya, nodemon --delay 3.2 untuk penundaan selama 3,2 detik.
      • --watch: Gunakan switch --watch untuk menentukan beberapa direktori atau berkas yang harus dipantau. Tambahkan satu switch --watch untuk setiap direktori yang ingin Anda pantau. Secara asali, direktori dan subdirektori saat ini telah dipantau, jadi dengan --watch Anda dapat mempersempitnya hanya ke subdirektori atau berkas tertentu.
      • --ignore: Gunakan switch --ignore untuk mengabaikan berkas, pola berkas, atau direktori tertentu.
      • --verbose: Keluaran verbose yang lebih banyak dengan informasi tentang berkas-berkas yang berubah sehingga memicu pemulaian ulang.

      Anda dapat melihat semua opsi yang tersedia dengan perintah berikut:

      Dengan menggunakan opsi ini, mari kita ciptakan perintah untuk memenuhi skenario berikut:

      • memantau direktori server
      • menentukan berkas dengan ekstensi .ts
      • mengabaikan berkas dengan akhiran .test.ts
      • mengeksekusi berkas (server/server.ts) dengan ts-node
      • menunggu selama tiga detik untuk memulai ulang setelah berkas berubah
      • nodemon --watch server --ext ts --exec ts-node --ignore '*.test.ts' --delay 3 server/server.ts

      Perintah ini mengombinasikan opsi --watch, --ext, --exec, --ignore, dan --delay untuk memenuhi kondisi skenario kita.

      Langkah 4 — Menggunakan Konfigurasi

      Dalam contoh sebelumnya, menambahkan switch konfigurasi saat menjalankan nodemon bisa menjadi cukup membosankan. Solusi yang lebih baik untuk proyek yang memerlukan konfigurasi spesifik adalah dengan menentukan konfigurasi ini dalam berkas nodemon.json.

      Misalnya, ini adalah konfigurasi yang sama seperti contoh baris perintah sebelumnya, tetapi ditempatkan di dalam berkas nodemon.json:

      nodemon.json

      {
        "watch": ["server"],
        "ext": "ts",
        "ignore": ["*.test.ts"],
        "delay": "3",
        "execMap": {
          "ts": "ts-node"
        }
      }
      

      Perhatikan penggunaan execMap alih-alih switch --exec. execMap memungkinkan Anda untuk menentukan biner yang harus digunakan untuk ekstensi berkas tertentu.

      Sebagai alternatif, jika Anda lebih memilih untuk tidak menambahkan berkas konfigurasi nodemon.json ke proyek, Anda dapat menambahkan konfigurasi ini ke berkas package.json di bawah kunci nodemonConfig:

      package.json

      {
        "name": "test-nodemon",
        "version": "1.0.0",
        "description": "",
        "nodemonConfig": {
          "watch": [
            "server"
          ],
          "ext": "ts",
          "ignore": [
            "*.test.ts"
          ],
          "delay": "3",
          "execMap": {
            "ts": "ts-node"
          }
        },
        // ...
      

      Setelah Anda membuat perubahan pada nodemon.json atau package.json, Anda kemudian dapat memulai nodemon dengan skrip yang diinginkan:

      nodemon akan mengambil konfigurasinya dan menggunakannya. Dengan cara ini, konfigurasi Anda dapat disimpan, dibagikan, dan diulang untuk menghindari salin-tempel atau kesalahan tik di baris perintah.

      Kesimpulan

      Dalam artikel ini, Anda telah mendalami cara menggunakan nodemon dengan aplikasi Node.js. Alat ini membantu mengotomatiskan proses memberhentikan dan memulai server Node untuk melihat perubahan.

      Untuk informasi lebih lanjut tentang fitur dan pemecahan masalah yang tersedia, lihat dokumentasi resmi.

      Jika Anda ingin mempelajari lebih lanjut tentang Node.js, lihat laman topik Node.js. kami untuk proyek latihan dan pemrograman.





      Source link

      Cara Mengakses Kamera Depan dan Belakang dengan getUserMedia() dari JavaScript


      Pengantar

      Kehadiran HTML5 memperkenalkan API dengan akses ke peranti keras perangkat, termasuk API MediaDevices. API ini memberikan akses ke perangkat masukan media seperti audio dan video.

      Dengan bantuan API ini, pengembang dapat mengakses perangkat audio dan video untuk mengalirkan dan menampilkan umpan video langsung di peramban. Dalam tutorial ini, Anda akan mengakses umpan video dari perangkat pengguna dan menampilkannya di peramban menggunakan metode getUserMedia.

      API getUserMedia memanfaatkan perangkat masukan media untuk menghasilkan MediaStream. MediaStream ini berisi jenis media yang diminta, baik audio atau video. Menggunakan aliran yang dikembalikan dari API, umpan video dapat ditampilkan di peramban, yang berguna untuk komunikasi waktu nyata di peramban.

      Ketika digunakan bersama API Rekaman MediaStream, Anda dapat merekam dan menyimpan data media yang ditangkap di peramban. API ini hanya bekerja di asal yang aman seperti API lainnya yang baru diperkenalkan, tetapi API ini juga bekerja di localhost dan URL berkas.

      Prasyarat

      Tutorial ini pertama-tama akan menjelaskan konsep dan mendemonstrasikan contoh dengan Codepen. Di langkah terakhir, Anda akan menciptakan umpan video yang berfungsi untuk peramban.

      Langkah 1 — Memeriksa Dukungan Perangkat

      Pertama-tama, Anda akan melihat cara memeriksa apakah peramban pengguna mendukung API mediaDevices. API ini ada di dalam antarmuka navigator dan berisi keadaan dan identitas saat ini dari agen pengguna. Pemeriksaan dilakukan dengan kode berikut yang dapat ditempelkan ke Codepen:

      if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) {
        console.log("Let's get this party started")
      }
      

      Pertama-tama, ini memeriksa apakah API mediaDevices ada di dalam navigator, lalu memeriksa apakah API getUserMedia tersedia di dalam mediaDevices. Jika ini menampilkan true, Anda dapat memulai.

      Langkah 2 — Meminta Izin Pengguna

      Setelah mengonfirmasi dukungan peramban untuk getUserMedia, Anda perlu meminta izin untuk menggunakan perangkat masukan media pada agen pengguna. Biasanya, setelah pengguna memberikan izin, Promise diberikan yang terselesaikan menjadi aliran media. Promise ini tidak diberikan ketika izin ditolak oleh pengguna, yang memblokir akses ke perangkat ini.

      Tempelkan baris berikut ke Codepen untuk meminta izin:

      navigator.mediaDevices.getUserMedia({video: true})
      

      Objek yang diberikan sebagai argumen untuk metode getUserMedia disebut constraints. Ini menentukan perangkat masukan media yang Anda minta izinnya untuk diakses. Misalnya, jika objek berisi audio: true, pengguna akan diminta memberikan akses ke perangkat masukan audio.

      Bagian ini akan membahas tentang konsep umum dari constraints. Objek constraints adalah suatu objek MediaStreamConstraints yang menentukan jenis media yang diminta dan persyaratan dari setiap jenis media. Anda dapat menentukan persyaratan untuk aliran yang diminta menggunakan objek constraints, seperti resolusi dari aliran yang digunakan (front, back).

      Anda harus menentukan baik audio atau video saat membuat permintaan. NotFoundError akan dihasilkan jika jenis media yang diminta tidak dapat ditemukan di peramban pengguna.

      Jika Anda berniat meminta aliran video dari resolusi 1280 x 720, Anda dapat memperbarui objek constraints agar terlihat seperti ini:

      {
        video: {
          width: 1280,
          height: 720,
        }
      }
      

      Dengan pembaruan ini, peramban akan mencoba mencocokkan pengaturan kualitas yang ditentukan untuk aliran tersebut. Jika perangkat video tidak dapat memberikan resolusi ini, peramban akan memberikan resolusi lain yang tersedia.

      Untuk memastikan peramban memberikan resolusi yang tidak lebih rendah dari yang disediakan sebelumnya, Anda harus memastikan untuk menggunakan properti min. Berikut ini adalah cara Anda dapat memperbarui objek constraints untuk menyertakan properti min:

      {
        video: {
          width: {
            min: 1280,
          },
          height: {
            min: 720,
          }
        }
      }
      

      Ini akan memastikan bahwa resolusi aliran tersebut setidaknya akan sebesar 1280 x 720. Jika persyaratan minimum ini tidak dapat terpenuhi, promise akan ditolak dengan OverconstrainedError.

      Dalam beberapa kasus, Anda mungkin khawatir tentang menyimpan data dan perlu membuat aliran tidak melampaui resolusi yang ditetapkan. Ini dapat menjadi berguna ketika pengguna berada dalam paket yang terbatas. Untuk mengaktifkan fungsionalitas ini, perbarui objek constraints untuk memuat bidang max:

      {
        video: {
          width: {
            min: 1280,
            max: 1920,
          },
          height: {
            min: 720,
            max: 1080
          }
        }
      }
      

      Dengan pengaturan ini, peramban akan memastikan bahwa aliran yang diberikan tidak lebih kecil dari 1280 x 720 dan tidak melebihi 1920 x 1080.

      Ketentuan lain yang dapat digunakan mencakup exact dan ideal. Pengaturan ideal biasanya digunakan bersama properti min dan max untuk menemukan kemungkinan pengaturan terbaik yang paling dekat dengan nilai ideal yang disediakan.

      Anda dapat memperbarui constraints untuk menggunakan kata kunci ideal:

      {
        video: {
          width: {
            min: 1280,
            ideal: 1920,
            max: 2560,
          },
          height: {
            min: 720,
            ideal: 1080,
            max: 1440
          }
        }
      }
      

      Untuk memberi tahu peramban agar menggunakan kamera depan atau belakang (di perangkat mobil) pada perangkat, Anda dapat menentukan properti facingMode dalam objek video:

      {
        video: {
          width: {
            min: 1280,
            ideal: 1920,
            max: 2560,
          },
          height: {
            min: 720,
            ideal: 1080,
            max: 1440
          },
          facingMode: 'user'
        }
      }
      

      Pengaturan ini akan menggunakan kamera yang selalu menghadap depan di semua perangkat. Untuk menggunakan kamera belakang di perangkat mobil, Anda dapat mengubah properti facingMode menjadi environment.

      {
        video: {
          ...
          facingMode: {
            exact: 'environment'
          }
        }
      }
      

      Langkah 4 — Menggunakan Metode enumerateDevices

      Ketika metode enumerateDevices digunakan, metode ini merespons dengan semua perangkat media masukan yang ada dan tersedia di PC pengguna.

      Dengan metode ini, Anda dapat memberi pengguna opsi-opsi tentang perangkat media yang digunakan untuk mengalirkan konten audio atau konten video. Metode ini menghasilkan Promise yang terselesaikan menjadi larik MediaDeviceInfo yang berisi informasi tentang setiap perangkat.

      Contoh cara menggunakan metode ini ditampilkan dalam cuplikan kode di bawah ini:

      async function getDevices() {
        const devices = await navigator.mediaDevices.enumerateDevices();
      }
      

      Respons sampel untuk setiap perangkat akan terlihat seperti yang berikut:

      {
        deviceId: "23e77f76e308d9b56cad920fe36883f30239491b8952ae36603c650fd5d8fbgj",
        groupId: "e0be8445bd846722962662d91c9eb04ia624aa42c2ca7c8e876187d1db3a3875",
        kind: "audiooutput",
        label: "",
      }
      

      Catatan: Label tidak akan diberikan kecuali ada aliran yang tersedia, atau jika pengguna telah memberikan izin akses perangkat.

      Langkah 5 — Menampilkan Aliran Video di Peramban

      Anda telah melewati proses meminta dan mendapatkan akses ke perangkat media, mengonfigurasi constraints untuk menyertakan resolusi yang diperlukan, dan memilih kamera yang Anda perlukan untuk merekam video.

      Setelah melewati semua langkah ini, setidaknya Anda ingin melihat apakah aliran tersebut bekerja sesuai dengan pengaturan yang dikonfigurasi. Untuk memastikan ini, Anda akan menggunakan elemen <video> untuk menampilkan aliran video di peramban.

      Seperti disebutkan sebelumnya, metode getUserMedia memberikan Promise yang dapat diselesaikan menjadi aliran. Aliran yang dihasilkan dapat dikonversi menjadi URL objek dengan metode createObjectURL. URL ini akan diatur sebagai sumber video.

      Anda akan menciptakan demo singkat yang membiarkan pengguna memilih dari daftar perangkat video mereka yang tersedia, yang menggunakan metode enumerateDevices.

      Ini adalah metode navigator.mediaDevices. Ini membuat daftar perangkat media yang tersedia, seperti mikrofon dan kamera. Ini memberikan Promise yang dapat diselesaikan menjadi larik objek yang memerinci perangkat media yang tersedia.

      Ciptakan berkas index.html dan perbarui konten dengan kode di bawah ini:

      index.html

      <!doctype html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport"
                content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
          <link rel="stylesheet" href="style.css">
          <title>Document</title>
      </head>
      <body>
      <div class="display-cover">
          <video autoplay></video>
          <canvas class="d-none"></canvas>
      
          <div class="video-options">
              <select name="" id="" class="custom-select">
                  <option value="">Select camera</option>
              </select>
          </div>
      
          <img class="screenshot-image d-none" alt="">
      
          <div class="controls">
              <button class="btn btn-danger play" title="Play"><i data-feather="play-circle"></i></button>
              <button class="btn btn-info pause d-none" title="Pause"><i data-feather="pause"></i></button>
              <button class="btn btn-outline-success screenshot d-none" title="ScreenShot"><i data-feather="image"></i></button>
          </div>
      </div>
      
      <script src="https://unpkg.com/feather-icons"></script>
      <script src="script.js"></script>
      </body>
      </html>
      

      Dalam cuplikan kode di atas, Anda telah menyiapkan elemen yang Anda perlukan dan beberapa kontrol untuk video. Yang juga disertakan adalah tombol untuk mengambil tangkapan layar dari umpan video saat ini.

      Sekarang, mari kita hias komponen ini sedikit.

      Ciptakan berkas style.css dan salin gaya berikut ke dalamnya. Bootstrap disertakan untuk mengurangi jumlah CSS yang harus ditulis agar komponennya berjalan.

      style.css

      .screenshot-image {
          width: 150px;
          height: 90px;
          border-radius: 4px;
          border: 2px solid whitesmoke;
          box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);
          position: absolute;
          bottom: 5px;
          left: 10px;
          background: white;
      }
      
      .display-cover {
          display: flex;
          justify-content: center;
          align-items: center;
          width: 70%;
          margin: 5% auto;
          position: relative;
      }
      
      video {
          width: 100%;
          background: rgba(0, 0, 0, 0.2);
      }
      
      .video-options {
          position: absolute;
          left: 20px;
          top: 30px;
      }
      
      .controls {
          position: absolute;
          right: 20px;
          top: 20px;
          display: flex;
      }
      
      .controls > button {
          width: 45px;
          height: 45px;
          text-align: center;
          border-radius: 100%;
          margin: 0 6px;
          background: transparent;
      }
      
      .controls > button:hover svg {
          color: white !important;
      }
      
      @media (min-width: 300px) and (max-width: 400px) {
          .controls {
              flex-direction: column;
          }
      
          .controls button {
              margin: 5px 0 !important;
          }
      }
      
      .controls > button > svg {
          height: 20px;
          width: 18px;
          text-align: center;
          margin: 0 auto;
          padding: 0;
      }
      
      .controls button:nth-child(1) {
          border: 2px solid #D2002E;
      }
      
      .controls button:nth-child(1) svg {
          color: #D2002E;
      }
      
      .controls button:nth-child(2) {
          border: 2px solid #008496;
      }
      
      .controls button:nth-child(2) svg {
          color: #008496;
      }
      
      .controls button:nth-child(3) {
          border: 2px solid #00B541;
      }
      
      .controls button:nth-child(3) svg {
          color: #00B541;
      }
      
      .controls > button {
          width: 45px;
          height: 45px;
          text-align: center;
          border-radius: 100%;
          margin: 0 6px;
          background: transparent;
      }
      
      .controls > button:hover svg {
          color: white;
      }
      

      Langkah selanjutnya adalah menambahkan fungsionalitas pada demo. Dengan menggunakan metode enumerateDevices, Anda akan mendapatkan perangkat video yang tersedia dan mengaturnya sebagai opsi di dalam elemen pilihan. Ciptakan berkas bernama script.js dan perbarui dengan cuplikan kode berikut:

      script.js

      feather.replace();
      
      const controls = document.querySelector('.controls');
      const cameraOptions = document.querySelector('.video-options>select');
      const video = document.querySelector('video');
      const canvas = document.querySelector('canvas');
      const screenshotImage = document.querySelector('img');
      const buttons = [...controls.querySelectorAll('button')];
      let streamStarted = false;
      
      const [play, pause, screenshot] = buttons;
      
      const constraints = {
        video: {
          width: {
            min: 1280,
            ideal: 1920,
            max: 2560,
          },
          height: {
            min: 720,
            ideal: 1080,
            max: 1440
          },
        }
      };
      
      const getCameraSelection = async () => {
        const devices = await navigator.mediaDevices.enumerateDevices();
        const videoDevices = devices.filter(device => device.kind === 'videoinput');
        const options = videoDevices.map(videoDevice => {
          return `<option value="${videoDevice.deviceId}">${videoDevice.label}</option>`;
        });
        cameraOptions.innerHTML = options.join('');
      };
      
      play.onclick = () => {
        if (streamStarted) {
          video.play();
          play.classList.add('d-none');
          pause.classList.remove('d-none');
          return;
        }
        if ('mediaDevices' in navigator && navigator.mediaDevices.getUserMedia) {
          const updatedConstraints = {
            ...constraints,
            deviceId: {
              exact: cameraOptions.value
            }
          };
          startStream(updatedConstraints);
        }
      };
      
      const startStream = async (constraints) => {
        const stream = await navigator.mediaDevices.getUserMedia(constraints);
        handleStream(stream);
      };
      
      const handleStream = (stream) => {
        video.srcObject = stream;
        play.classList.add('d-none');
        pause.classList.remove('d-none');
        screenshot.classList.remove('d-none');
        streamStarted = true;
      };
      
      getCameraSelection();
      

      Dalam cuplikan kode di atas, ada beberapa hal yang terjadi. Mari kita uraikan:

      1. feather.replace(): metode ini memanggil instans feather, yang merupakan ikon yang diatur untuk pengembangan web.
      2. Variabel constraints menyimpan konfigurasi awal untuk aliran. Ini akan diperluas untuk menyertakan perangkat media yang dipilih pengguna.
      3. getCameraSelection: fungsi ini memanggil metode enumerateDevices. Kemudian, Anda memfilter larik dari Promise yang terselesaikan dan memilih perangkat masukan video. Dari hasil yang terfilter, Anda membuat <option> untuk elemen <select>.
      4. Memanggil metode getUserMedia terjadi di dalam pendengar onclick dari tombol play. Di sini, Anda akan memeriksa apakah metode ini didukung oleh peramban pengguna sebelum memulai aliran.
      5. Selanjutnya, Anda akan memanggil fungsi startStream yang mengambil argumen constraints. Ini memanggil metode getUserMedia dengan constraints yang disediakan. handleStream dipanggil menggunakan aliran dari Promise yang terselesaikan. Metode ini mengatur aliran yang diberikan ke srcObject dari elemen video.

      Selanjutnya, Anda akan menambahkan pendengar ke tombol kontrol pada laman untuk melakukan pause (jeda), stop (berhenti), dan mengambil screenshots (tangkapan layar). Juga, Anda akan menambahkan pendengar ke elemen <select> untuk memperbarui constraints aliran dengan perangkat video yang dipilih.

      Perbarui berkas script.js dengan kode di bawah ini:

      script.js

      ...
      cameraOptions.onchange = () => {
        const updatedConstraints = {
          ...constraints,
          deviceId: {
            exact: cameraOptions.value
          }
        };
        startStream(updatedConstraints);
      };
      
      const pauseStream = () => {
        video.pause();
        play.classList.remove('d-none');
        pause.classList.add('d-none');
      };
      
      const doScreenshot = () => {
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        canvas.getContext('2d').drawImage(video, 0, 0);
        screenshotImage.src = canvas.toDataURL('image/webp');
        screenshotImage.classList.remove('d-none');
      };
      
      pause.onclick = pauseStream;
      screenshot.onclick = doScreenshot;
      

      Sekarang, saat Anda membuka berkas index.html di peramban, mengeklik tombol Play akan memulai aliran.

      Berikut adalah demo yang lengkap:

      Kesimpulan

      Tutorial ini memperkenalkan API getUserMedia. Ini adalah tambahan yang menarik untuk HTML5 yang mempermudah proses penangkapan media di web.

      API menggunakan parameter (constraints) yang dapat digunakan untuk mengonfigurasi akses ke perangkat masukan audio dan video. Ini juga dapat digunakan untuk menentukan resolusi video yang diperlukan untuk aplikasi Anda.

      Anda dapat memperpanjang demo lebih lanjut untuk memberi pengguna dengan suatu opsi untuk menyimpan tangkapan layar yang diambil, begitu juga dengan merekam dan menyimpan data video serta audio dengan bantuan dari API Rekaman MediaStream.



      Source link

      Cara Membangun Paginasi Khusus dengan React


      Pengantar

      Kita sering terlibat dalam pembuatan aplikasi web yang mengharuskan kita mengambil set catatan data yang besar dari server jauh, API, atau basis data. Jika Anda membangun sistem pembayaran, misalnya, sistem ini dapat mengambil ribuan transaksi. Jika contohnya adalah aplikasi media sosial, aplikasi ini dapat mengambil banyak komentar, profil, atau kegiatan pengguna. Apa pun kasusnya, ada beberapa solusi untuk menyajikan data dengan cara yang tidak menyulitkan pengguna akhir yang berinteraksi dengan aplikasi tersebut.

      Salah satu metode untuk menangani set data besar adalah menggunakan paginasi. Paginasi bekerja secara efektif saat Anda sudah mengetahui ukuran set data (total jumlah catatan dalam set data). Kedua, Anda hanya memuat potongan data yang diperlukan dari set data total berdasarkan interaksi pengguna akhir dengan kontrol paginasi. Ini adalah teknik yang digunakan untuk menampilkan hasil pencarian di Google Search.

      Dalam tutorial ini, kita akan mempelajari cara membangun komponen paginasi khusus dengan React untuk melakukan paginasi pada set data yang besar. Anda akan membangun tampilan terpaginasi dari negara-negara di dunia – suatu set data dengan ukuran yang sudah diketahui.

      Berikut ini adalah peragaan yang akan Anda bangun dalam tutorial ini:

      Tangkapan Layar Aplikasi Demo — menampilkan negara-negara di dunia

      Prasyarat

      Untuk menyelesaikan tutorial ini, Anda akan memerlukan:

      Tutorial ini diverifikasi dengan Node v14.2.0, npm v6.14.4, react v16.13.1, dan react-scripts v3.4.1.

      Langkah 1 — Menyiapkan Proyek

      Mulai aplikasi React yang baru menggunakan perintah create-react-app. Anda dapat menamakan aplikasi sesuai keinginan Anda, tetapi tutorial ini akan menamakannya react-pagination:

      • npx create-react-app react-pagination

      Selanjutnya, Anda akan menginstal dependensi yang diperlukan untuk aplikasi Anda. Pertama-tama, gunakan jendela terminal untuk bernavigasi ke direktori proyek:

      Jalankan perintah berikut untuk menginstal dependensi yang diperlukan:

      • npm install bootstrap@4.1.0 prop-types@15.6.1 react-flags@0.1.13 countries-api@2.0.1 node-sass@4.14.1

      Ini akan menginstal bootstrap, prop-types, react-flags, countries-api, dan node-sass.

      Anda menginstal paket bootstrap sebagai dependensi untuk aplikasi karena Anda akan membutuhkan beberapa penataan gaya asali. Anda juga akan menggunakan gaya dari komponen pagination Bootstrap.

      Untuk menyertakan Bootstrap dalam aplikasi, edit berkas src/index.js:

      Dan tambahkan baris berikut sebelum pernyataan import lainnya:

      src/index.js

      import "bootstrap/dist/css/bootstrap.min.css";
      

      Sekarang, penataan gaya Bootstrap akan tersedia di seluruh aplikasi Anda.

      Anda juga telah menginstal react-flags sebagai dependensi untuk aplikasi Anda. Untuk mendapatkan akses ke ikon bendera dari aplikasi, Anda perlu menyalin citra ikon ke direktori public aplikasi Anda.

      Buat direktori img dalam direktori public Anda:

      Salin berkas citra dalam flags ke img:

      • cp -R node_modules/react-flags/vendor/flags public/img

      Ini menyediakan salinan dari semua citra react-flag untuk aplikasi Anda.

      Karena Anda sudah menyertakan sebagian dependensi, mulailah aplikasi dengan menjalankan perintah berikut menggunakan npm dari direktori proyek react-pagination:

      Karena Anda telah memulai aplikasi, pengembangan dapat dimulai. Perhatikan bahwa tab peramban telah dibuka untuk Anda dengan fungsionalitas pemuatan ulang langsung agar tetap sinkron dengan aplikasi seiring Anda mengembangkannya.

      Di titik ini, tampilan aplikasi akan terlihat seperti tangkapan layar berikut:

      Tampilan Awal – Layar Welcome to React

      Anda kini siap untuk mulai menciptakan komponen.

      Langkah 2 — Menciptakan Komponen CountryCard

      Dalam langkah ini, Anda akan menciptakan komponen CountryCard. Komponen CountryCard merender nama, wilayah, dan bendera dari negara yang diberikan.

      Pertama-tama, mari kita ciptakan direktori component dalam direktori src:

      Kemudian, ciptakan berkas CountryCard.js yang baru dalam direktori src/components:

      • nano src/components/CountryCard.js

      Lalu, tambahkan snippet kode berikut padanya:

      src/components/CountryCard.js

      import React from 'react';
      import PropTypes from 'prop-types';
      import Flag from 'react-flags';
      
      const CountryCard = props => {
        const {
          cca2: code2 = '', region = null, name = {}
        } = props.country || {};
      
        return (
          <div className="col-sm-6 col-md-4 country-card">
            <div className="country-card-container border-gray rounded border mx-2 my-3 d-flex flex-row align-items-center p-0 bg-light">
              <div className="h-100 position-relative border-gray border-right px-2 bg-white rounded-left">
                <Flag country={code2} format="png" pngSize={64} basePath="./img/flags" className="d-block h-100" />
              </div>
              <div className="px-3">
                <span className="country-name text-dark d-block font-weight-bold">{ name.common }</span>
                <span className="country-region text-secondary text-uppercase">{ region }</span>
              </div>
            </div>
          </div>
        )
      }
      
      CountryCard.propTypes = {
        country: PropTypes.shape({
          cca2: PropTypes.string.isRequired,
          region: PropTypes.string.isRequired,
          name: PropTypes.shape({
            common: PropTypes.string.isRequired
          }).isRequired
        }).isRequired
      };
      
      export default CountryCard;
      

      Komponen CountryCard membutuhkan properti country yang berisi data tentang negara yang harus dirender. Seperti terlihat dalam propTypes untuk komponen CountryCard, objek properti country harus berisi data berikut:

      • cca2 - kode negara 2 digit
      • region - wilayah negara (misalnya: “Afrika”)
      • name.common - nama umum dari negara tersebut (misalnya: “Nigeria”)

      Berikut ini adalah objek negara sampel:

      {
        cca2: "NG",
        region: "Africa",
        name: {
          common: "Nigeria"
        }
      }
      

      Juga, perhatikan cara Anda merender bendera negara menggunakan paket react-flags. Anda dapat membaca dokumentasi react-flagsuntuk mempelajari lebih lanjut tentang properti yang diperlukan dan cara menggunakan paket tersebut.

      Kini Anda telah menyelesaikan satu komponen CountryCard. Pada akhirnya, Anda akan menggunakan CountryCard berkali-kali untuk menampilkan bendera dan informasi negara yang berbeda dalam aplikasi Anda.

      Dalam langkah ini, Anda akan menciptakan komponen Pagination. Komponen Pagination berisi logika untuk membangun, merender, dan beralih halaman pada kontrol paginasi.

      Ciptakan berkas Pagination.js yang baru dalam direktori src/components:

      • nano src/components/Pagination.js

      Lalu, tambahkan cuplikan kode berikut padanya:

      src/components/Pagination.js

      import React, { Component, Fragment } from 'react';
      import PropTypes from 'prop-types';
      
      class Pagination extends Component {
        constructor(props) {
          super(props);
          const { totalRecords = null, pageLimit = 30, pageNeighbours = 0 } = props;
      
          this.pageLimit = typeof pageLimit === 'number' ? pageLimit : 30;
          this.totalRecords = typeof totalRecords === 'number' ? totalRecords : 0;
      
          // pageNeighbours can be: 0, 1 or 2
          this.pageNeighbours = typeof pageNeighbours === 'number'
            ? Math.max(0, Math.min(pageNeighbours, 2))
            : 0;
      
          this.totalPages = Math.ceil(this.totalRecords / this.pageLimit);
      
          this.state = { currentPage: 1 };
        }
      }
      
      Pagination.propTypes = {
        totalRecords: PropTypes.number.isRequired,
        pageLimit: PropTypes.number,
        pageNeighbours: PropTypes.number,
        onPageChanged: PropTypes.func
      };
      
      export default Pagination;
      

      Komponen Pagination dapat menggunakan empat properti khusus seperti yang ditentukan dalam objek propTypes.

      • onPageChanged adalah fungsi yang dipanggil dengan data dari keadaan paginasi saat ini hanya ketika halaman saat ini berubah.
      • totalRecords menunjukkan jumlah total catatan yang harus dipaginasikan. Ini wajib diisi.
      • pageLimit menunjukkan jumlah catatan yang ditampilkan per halaman. Jika tidak ditentukan, nilai asalinya adalah 30 seperti didefinisikan dalam constructor().
      • pageNeighbours menunjukkan jumlah nomor halaman tambahan yang ditampilkan di setiap sisi dari halaman saat ini. Nilai minimumnya adalah 0, dan nilai maksimumnya adalah 2. Jika tidak ditentukan, nilai asalinya adalah 0 seperti didefinisikan dalam constructor().

      Gambar berikut ini mengilustrasikan efek dari nilai-nilai yang berbeda dari properti pageNeighbours:

      Ilustrasi Page Neighbours

      Dalam fungsi constructor(), Anda melakukan komputasi halaman total seperti berikut:

      this.totalPages = Math.ceil(this.totalRecords / this.pageLimit);
      

      Perhatikan bahwa Anda menggunakan Math.ceil() di sini yang memastikan bahwa Anda mendapatkan nilai integer untuk jumlah total halaman. Ini juga memastikan bahwa kelebihan catatan ditangkap dalam halaman terakhir, khususnya dalam kasus saat jumlah kelebihan catatan kurang dari jumlah catatan yang harus ditampilkan per halaman.

      Terakhir, Anda menginisialisasi keadaan dengan properti currentPage menjadi 1. Anda memerlukan properti keadaan ini untuk melacak halaman yang aktif saat ini secara internal.

      Selanjutnya, Anda akan menciptakan metode untuk menghasilkan nomor halaman.

      Setelah import tetapi sebelum kelas Pagination, tambahkan konstanta berikut dan fungsi range:

      src/components/Pagination.js

      // ...
      
      const LEFT_PAGE = 'LEFT';
      const RIGHT_PAGE = 'RIGHT';
      
      /**
       * Helper method for creating a range of numbers
       * range(1, 5) => [1, 2, 3, 4, 5]
       */
      const range = (from, to, step = 1) => {
        let i = from;
        const range = [];
      
        while (i <= to) {
          range.push(i);
          i += step;
        }
      
        return range;
      }
      

      Dalam kelas Pagination, setelah constructor, tambahkan metode fetchPageNumbers berikut:

      src/components/Pagination.js

      class Pagination extends Component {
        // ...
      
        /**
         * Let's say we have 10 pages and we set pageNeighbours to 2
         * Given that the current page is 6
         * The pagination control will look like the following:
         *
         * (1) < {4 5} [6] {7 8} > (10)
         *
         * (x) => terminal pages: first and last page(always visible)
         * [x] => represents current page
         * {...x} => represents page neighbours
         */
        fetchPageNumbers = () => {
          const totalPages = this.totalPages;
          const currentPage = this.state.currentPage;
          const pageNeighbours = this.pageNeighbours;
      
          /**
           * totalNumbers: the total page numbers to show on the control
           * totalBlocks: totalNumbers + 2 to cover for the left(<) and right(>) controls
           */
          const totalNumbers = (this.pageNeighbours * 2) + 3;
          const totalBlocks = totalNumbers + 2;
      
          if (totalPages > totalBlocks) {
            const startPage = Math.max(2, currentPage - pageNeighbours);
            const endPage = Math.min(totalPages - 1, currentPage + pageNeighbours);
            let pages = range(startPage, endPage);
      
            /**
             * hasLeftSpill: has hidden pages to the left
             * hasRightSpill: has hidden pages to the right
             * spillOffset: number of hidden pages either to the left or to the right
             */
            const hasLeftSpill = startPage > 2;
            const hasRightSpill = (totalPages - endPage) > 1;
            const spillOffset = totalNumbers - (pages.length + 1);
      
            switch (true) {
              // handle: (1) < {5 6} [7] {8 9} (10)
              case (hasLeftSpill && !hasRightSpill): {
                const extraPages = range(startPage - spillOffset, startPage - 1);
                pages = [LEFT_PAGE, ...extraPages, ...pages];
                break;
              }
      
              // handle: (1) {2 3} [4] {5 6} > (10)
              case (!hasLeftSpill && hasRightSpill): {
                const extraPages = range(endPage + 1, endPage + spillOffset);
                pages = [...pages, ...extraPages, RIGHT_PAGE];
                break;
              }
      
              // handle: (1) < {4 5} [6] {7 8} > (10)
              case (hasLeftSpill && hasRightSpill):
              default: {
                pages = [LEFT_PAGE, ...pages, RIGHT_PAGE];
                break;
              }
            }
      
            return [1, ...pages, totalPages];
          }
      
          return range(1, totalPages);
        }
      }
      

      Di sini, pertama-tama Anda mendefinisikan dua konstanta: LEFT_PAGE dan RIGHT_PAGE. Konstanta ini akan digunakan untuk menunjukkan titik-titik dengan kontrol halaman untuk membalik ke kiri dan kanan, secara berurutan.

      Anda juga mendefinisikan fungsi range() pembantu yang dapat membantu Anda menghasilkan rentang halaman.

      Catatan: Jika Anda menggunakan pustaka utilitas seperti Lodashdalam proyek, Anda dapat menggunakan fungsi _.range() yang disediakan oleh Lodash sebagai gantinya. Cuplikan kode berikut menunjukkan perbedaan antara fungsi range() yang baru saja Anda definisikan dan fungsi dari Lodash:

      range(1, 5); // returns [1, 2, 3, 4, 5]
      _.range(1, 5); // returns [1, 2, 3, 4]
      

      Selanjutnya, Anda mendefinisikan metode fetchPageNumbers() dalam kelas Pagination. Metode ini menangani logika inti untuk menghasilkan nomor halaman yang ditampilkan pada kontrol paginasi. Anda ingin halaman pertama dan halaman terakhir agar selalu terlihat.

      Pertama-tama, definisikan beberapa variabel. totalNumbers mewakili jumlah nomor halaman total yang akan ditampilkan pada kontrol. totalBlocks mewakili jumlah nomor halaman total yang ditampilkan ditambah dua blok tambahan untuk indikator halaman kiri dan kanan.

      Jika totalPages tidak lebih besar dari totalBlocks, Anda menghasilkan rentang nomor dari 1 hingga totalPages. Sebaliknya, Anda menghasilkan larik dari nomor halaman, dengan LEFT_PAGE dan RIGHT_PAGE di titik-titik tempat Anda memiliki halaman yang tercecer ke kiri dan kanan, secara berurutan.

      Meskipun begitu, perhatikan bahwa kontrol paginasi Anda memastikan bahwa halaman pertama dan halaman terakhir selalu terlihat. Kontrol halaman kiri dan kanan muncul ke arah dalam.

      Sekarang, Anda akan menambahkan metode render() untuk memungkinkan Anda merender kontrol paginasi.

      Dalam kelas Pagination, setelah constructor dan metodefetchPageNumbers, tambahkan metode render berikut:

      src/components/Pagination.js

      class Pagination extends Component {
        // ...
      
        render() {
          if (!this.totalRecords || this.totalPages === 1) return null;
      
          const { currentPage } = this.state;
          const pages = this.fetchPageNumbers();
      
          return (
            <Fragment>
              <nav aria-label="Countries Pagination">
                <ul className="pagination">
                  { pages.map((page, index) => {
      
                    if (page === LEFT_PAGE) return (
                      <li key={index} className="page-item">
                        <a className="page-link" href="https://www.digitalocean.com/community/tutorials/#" aria-label="Previous" onClick={this.handleMoveLeft}>
                          <span aria-hidden="true">&laquo;</span>
                          <span className="sr-only">Previous</span>
                        </a>
                      </li>
                    );
      
                    if (page === RIGHT_PAGE) return (
                      <li key={index} className="page-item">
                        <a className="page-link" href="https://www.digitalocean.com/community/tutorials/#" aria-label="Next" onClick={this.handleMoveRight}>
                          <span aria-hidden="true">&raquo;</span>
                          <span className="sr-only">Next</span>
                        </a>
                      </li>
                    );
      
                    return (
                      <li key={index} className={`page-item${ currentPage === page ? ' active' : ''}`}>
                        <a className="page-link" href="https://www.digitalocean.com/community/tutorials/#" onClick={ this.handleClick(page) }>{ page }</a>
                      </li>
                    );
      
                  }) }
      
                </ul>
              </nav>
            </Fragment>
          );
        }
      }
      

      Di sini, Anda menghasilkan array nomor halaman dengan memanggil metode fetchPageNumbers() yang Anda ciptakan sebelumnya. Kemudian, Anda merender setiap nomor halaman menggunakan Array.prototype.map(). Perhatikan bahwa Anda mendaftarkan penangan peristiwa klik di setiap nomor halaman yang dirender untuk menangani klik.

      Juga, perhatikan bahwa kontrol paginasi tidak akan dirender jika prop totalRecords tidak diberikan dengan benar ke komponen Pagination atau jika hanya ada 1 halaman.

      Terakhir, Anda akan mendefinisikan metode penangan peristiwa.

      Dalam kelas Pagination, setelah constructor dan metode fetchPageNumbers serta metode render, tambahkan yang berikut:

      src/components/Pagination.js

      class Pagination extends Component {
        // ...
      
        componentDidMount() {
          this.gotoPage(1);
        }
      
        gotoPage = page => {
          const { onPageChanged = f => f } = this.props;
          const currentPage = Math.max(0, Math.min(page, this.totalPages));
          const paginationData = {
            currentPage,
            totalPages: this.totalPages,
            pageLimit: this.pageLimit,
            totalRecords: this.totalRecords
          };
      
          this.setState({ currentPage }, () => onPageChanged(paginationData));
        }
      
        handleClick = page => evt => {
          evt.preventDefault();
          this.gotoPage(page);
        }
      
        handleMoveLeft = evt => {
          evt.preventDefault();
          this.gotoPage(this.state.currentPage - (this.pageNeighbours * 2) - 1);
        }
      
        handleMoveRight = evt => {
          evt.preventDefault();
          this.gotoPage(this.state.currentPage + (this.pageNeighbours * 2) + 1);
        }
      }
      

      Anda mendefinisikan metode gotoPage() yang memodifikasi keadaan dan mengatur currentPage menjadi halaman yang ditentukan. Ini memastikan bahwa argumen page memiliki nilai minimum 1 dan nilai maksimum sebesar jumlah total halaman. Pada akhirnya, ini memanggil fungsi onPageChanged() yang diberikan sebagai prop, dengan data menunjukkan keadaan paginasi yang baru.

      Saat komponen terpasang, Anda pergi ke halaman pertama dengan memanggil this.gotoPage(1) seperti yang ditampilkan dalam metode siklus hidup componentDidMount().

      Perhatikan cara Anda menggunakan (this.pageNeighbours * 2) dalam handleMoveLeft() dan handleMoveRight() untuk menggeser nomor halaman ke kiri dan ke kanan secara berurutan berdasarkan nomor halaman saat ini.

      Berikut adalah demo dari interaksi pergerakan dari kiri ke kanan.

      Pergerakan Kiri-Kanan dari interaksi

      Kini Anda telah menyelesaikan komponen Pagination. Pengguna akan dapat berinteraksi dengan kontrol navigasi dalam komponen ini untuk menampilkan halaman berbeda dari bendera.

      Langkah 4 — Membangun Komponen App

      Karena Anda memiliki komponen CountryCard dan Pagination, Anda dapat menggunakannya dalam komponen App.

      Modifikasi berkas App.js dalam direktori src:

      Gantikan konten dari App.js dengan baris kode berikut:

      src/App.js

      import React, { Component } from 'react';
      import Countries from 'countries-api';
      import './App.css';
      import Pagination from './components/Pagination';
      import CountryCard from './components/CountryCard';
      
      class App extends Component {
        state = { allCountries: [], currentCountries: [], currentPage: null, totalPages: null }
      
        componentDidMount() {
          const { data: allCountries = [] } = Countries.findAll();
          this.setState({ allCountries });
        }
      
        onPageChanged = data => {
          const { allCountries } = this.state;
          const { currentPage, totalPages, pageLimit } = data;
          const offset = (currentPage - 1) * pageLimit;
          const currentCountries = allCountries.slice(offset, offset + pageLimit);
      
          this.setState({ currentPage, currentCountries, totalPages });
        }
      }
      
      export default App;
      

      Di sini, Anda menginisialisasi keadaan komponen App dengan atribut berikut:

      • allCountries - Ini adalah larik dari semua negara dalam aplikasi Anda. Diinisialisasi menjadi larik yang kosong ([]).
      • currentCountries - Ini adalah larik dari semua negara yang ditampilkan pada halaman aktif saat ini. Diinisialisasi menjadi larik yang kosong ([]).
      • currentPage - Nomor halaman dari halaman yang aktif saat ini. Diinisialisasi menjadi null.
      • totalPages - Jumlah total halaman untuk semua catatan negara. Diinisialisasi menjadi null.

      Selanjutnya, dalam metode siklus hidup componentDidMount(), Anda mengambil semua negara-negara di dunia menggunakan paket countries-api dengan memanggil Countries.findAll(). Kemudian, Anda memperbarui keadaan aplikasi, mengatur allCountries untuk memuat semua negara dunia. Anda dapat melihat dokumentasi countries-apiuntuk mempelajari lebih lanjut tentang paket tersebut.

      Terakhir, Anda mendefinisikan metode onPageChanged(), yang akan dipanggil setiap kali Anda bernavigasi ke halaman baru dari kontrol paginasi. Metode ini akan diberikan ke properti onPageChanged dari komponen Pagination.

      Ada dua baris yang layak diperhatikan dalam metode ini. Yang pertama adalah baris ini:

      const offset = (currentPage - 1) * pageLimit;
      

      Nilai offset menunjukkan indeks permulaan untuk mengambil catatan halaman saat ini. Menggunakan (currentPage - 1) memastikan bahwa offset berbasis nol. Mari kita anggap sebagai contoh, bahwa Anda menampilkan 25 catatan per halaman, dan Anda saat ini sedang melihat halaman 5. Kemudian, offset adalah ((5 - 1) * 25 = 100).

      Misalnya, jika Anda mengambil catatan sesuai permintaan dari basis data, ini adalah kueri SQL sampel untuk menunjukkan kepada Anda bagaimana offset dapat digunakan:

      SELECT * FROM `countries` LIMIT 100, 25
      

      Karena Anda tidak mengambil catatan dari basis data atau sumber eksternal, Anda memerlukan cara untuk mengekstrak potongan catatan yang diperlukan guna ditampilkan di halaman saat ini.

      Yang kedua adalah baris ini:

      const currentCountries = allCountries.slice(offset, offset + pageLimit);
      

      Di sini, Anda menggunakan metode Array.prototype.slice() untuk mengekstrak potongan catatan yang diperlukan dari allCountries dengan memberikan offset sebagai indeks permulaan untuk irisan dan (offset + pageLimit) sebagai indeks untuk mengakhiri irisan.

      Catatan: Dalam tutorial ini, Anda tidak mengambil catatan dari sumber eksternal apa pun. Dalam aplikasi nyata, Anda mungkin akan mengambil catatan dari basis data atau API. Logika untuk mengambil catatan dapat diterapkam dalam metode onPageChanged() dari komponen App.

      Mari kita anggap Anda memiliki titik akhir API fiktif /api/countries?page={current_page}&limit={page_limit}. Snippet berikut menunjukkan cara Anda dapat mengambil negara-negara sesuai permintaan dari API dengan menggunakan paket HTTP axios:

      onPageChanged = data => {
        const { currentPage, totalPages, pageLimit } = data;
      
        axios.get(`/api/countries?page=${currentPage}&limit=${pageLimit}`)
          .then(response => {
            const currentCountries = response.data.countries;
            this.setState({ currentPage, currentCountries, totalPages });
          });
      }
      

      Sekarang, Anda dapat menyelesaikan komponen App dengan menambahkan metode render().

      Dalam kelas App, tetapi setelah componentDidMount dan onPageChanged, tambahkan metode render berikut:

      src/App.js

      class App extends Component {
        // ... other methods here ...
      
        render() {
          const { allCountries, currentCountries, currentPage, totalPages } = this.state;
          const totalCountries = allCountries.length;
      
          if (totalCountries === 0) return null;
      
          const headerClass = ['text-dark py-2 pr-4 m-0', currentPage ? 'border-gray border-right' : ''].join(' ').trim();
      
          return (
            <div className="container mb-5">
              <div className="row d-flex flex-row py-5">
                <div className="w-100 px-4 py-5 d-flex flex-row flex-wrap align-items-center justify-content-between">
                  <div className="d-flex flex-row align-items-center">
                    <h2 className={headerClass}>
                      <strong className="text-secondary">{totalCountries}</strong> Countries
                    </h2>
                    { currentPage && (
                      <span className="current-page d-inline-block h-100 pl-4 text-secondary">
                        Page <span className="font-weight-bold">{ currentPage }</span> / <span className="font-weight-bold">{ totalPages }</span>
                      </span>
                    ) }
                  </div>
                  <div className="d-flex flex-row py-4 align-items-center">
                    <Pagination totalRecords={totalCountries} pageLimit={18} pageNeighbours={1} onPageChanged={this.onPageChanged} />
                  </div>
                </div>
                { currentCountries.map(country => <CountryCard key={country.cca3} country={country} />) }
              </div>
            </div>
          );
        }
      }
      

      Dalam metode render(), Anda merender jumlah total negara, halaman saat ini, jumlah total halaman, kontrol <Pagination>, kemudian <CountryCard> untuk setiap negara pada halaman saat ini.

      Perhatikan bahwa Anda memberikan metode onPageChanged() yang Anda definisikan sebelumnya ke properti onPageChanged dari kontrol <Pagination>. Ini sangat penting untuk menangkap perubahan halaman dari komponen Pagination. Anda juga menampilkan 18 negara per halaman.

      Di titik ini, aplikasi akan terlihat seperti tangkapan layar berikut:

      Tangkapan Layar Aplikasi dengan 248 negara tercantum dan nomor halaman di atas untuk menggeser setiap halaman

      Kini Anda memiliki komponen App yang menampilkan beberapa komponen CountryCard dan komponen Pagination yang memecah konten menjadi halaman yang terpisah. Selanjutnya, Anda akan menjelajahi penataan gaya dari aplikasi Anda.

      Langkah 5 — Menambah Gaya Khusus

      Anda mungkin telah memperhatikan bahwa Anda telah menambahkan beberapa kelas khusus pada komponen yang Anda ciptakan sebelumnya. Mari kita definisikan beberapa aturan gaya untuk kelas-kelas tersebut dalam berkas src/App.scss.

      Berkas App.scss akan terlihat seperti cuplikan kode berikut:

      src/App.scss

      /* Declare some variables */
      $base-color: #ced4da;
      $light-background: lighten(desaturate($base-color, 50%), 12.5%);
      
      .current-page {
        font-size: 1.5rem;
        vertical-align: middle;
      }
      
      .country-card-container {
        height: 60px;
        cursor: pointer;
        position: relative;
        overflow: hidden;
      }
      
      .country-name {
        font-size: 0.9rem;
      }
      
      .country-region {
        font-size: 0.7rem;
      }
      
      .current-page,
      .country-name,
      .country-region {
        line-height: 1;
      }
      
      // Override some Bootstrap pagination styles
      ul.pagination {
        margin-top: 0;
        margin-bottom: 0;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
      
        li.page-item.active {
          a.page-link {
            color: saturate(darken($base-color, 50%), 5%) !important;
            background-color: saturate(lighten($base-color, 7.5%), 2.5%) !important;
            border-color: $base-color !important;
          }
        }
      
        a.page-link {
          padding: 0.75rem 1rem;
          min-width: 3.5rem;
          text-align: center;
          box-shadow: none !important;
          border-color: $base-color !important;
          color: saturate(darken($base-color, 30%), 10%);
          font-weight: 900;
          font-size: 1rem;
      
          &:hover {
            background-color: $light-background;
          }
        }
      }
      

      Modifikasi berkas App.js Anda untuk merujuk ke App.scss alih-alih App.css.

      Catatan: Untuk informasi lebih lanjut tentang ini, lihat dokumentasi Menciptakan Aplikasi React.

      src/App.js

      import React, { Component } from 'react';
      import Countries from 'countries-api';
      import './App.scss';
      import Pagination from './components/Pagination';
      import CountryCard from './components/CountryCard';
      

      Setelah menambahkan gaya, kini aplikasi akan terlihat seperti tangkapan layar berikut:

      Tangkapan Layar Aplikasi halaman 1 dari 14, dengan Gaya

      Kini Anda memiliki aplikasi yang lengkap dengan penataan gaya khusus tambahan. Anda dapat menggunakan gaya khusus untuk memodifikasi dan meningkatkan penataan gaya asali apa pun yang disediakan oleh pustaka seperti Bootstrap.

      Kesimpulan

      Dalam tutorial ini, Anda telah menciptakan widget paginasi khusus dalam aplikasi React. Meskipun Anda tidak membuat panggilan ke API atau berinteraksi dengan ujung belakang basis data apa pun dalam tutorial ini, aplikasi Anda mungkin menuntut interaksi tersebut. Anda tidak dibatasi dengan cara apa pun dalam hal pendekatan yang digunakan di tutorial ini - Anda dapat mengembangkannya sesuai keinginan untuk menyesuaikan keperluan aplikasi Anda.

      Untuk kode sumber yang lengkap dari tutorial ini, lihat pagination-demorepositori [build-react-pagination-demo] di GitHub. Anda juga bisa mendapatkan demo langsung dari tutorial ini di Code Sandbox.

      Jika Anda ingin mempelajari lebih lanjut tentang React, lihat seri Cara Melakukan Pengodean di React.js dari kami, atau baca halaman topik React kami untuk proyek pemrograman dan latihan.



      Source link