oleh “Juboye Johnson”

useReducer React hook rumit dan agak rumit untuk dikembangkan pada awalnya. Namun, setelah Anda memahami kaitan ini dan cara menggunakannya, hal ini membuat pengelolaan negara menjadi sesederhana mungkin, terutama dalam aspek pelacakan berbagai bagian negara bagian yang diimplementasikan menggunakan kait useState.

Pada artikel ini, kita akan melihat hook useReducer dan mengapa ini merupakan pilihan yang lebih baik untuk mengelola keadaan kompleks di React daripada hook useState. Tutorial ini ramah bagi pemula, dan Anda perlu menginstal Node.js dan React.

Manajemen negara

Kita sering mendengar tentang negara, perubahan negara, dan pengelolaan negara. Apa sebenarnya negara bagian itu? Kami dapat mengartikannya secara harfiah dengan mengatakan bahwa ini adalah kondisi program Anda saat ini, namun hal tersebut mungkin tidak terlalu mudah untuk dipahami. Dalam pemrograman, status hanyalah kombinasi dari semua data yang saat ini kita miliki di aplikasi kita, data yang digunakan dan dikembalikan oleh program Anda yang sedang berjalan.

Apa sebenarnya pengelolaan negara itu? Menurut Wikipedia, “ Manajemen status mengacu pada pengelolaan status satu atau lebih kontrol antarmuka pengguna seperti bidang teks, tombol OK, tombol radio, dll.”

useReduce vs useState

Bisakah pengelolaan negara dilakukan tanpa menggunakan useState? Pertanyaan yang tersebar luas dengan lebih dari 300.000+ hasil di Google:

Jika Anda mendapati diri Anda melacak beberapa bagian keadaan yang mengandalkan logika kompleks, kait useReducer mungkin lebih baik. Mari kita buat aplikasi yang bisa menambah dan mengurangi angka menggunakan hook itu dan lihat seberapa efisiennya.

Menetapkan Kawasan Pengembangan

Kita perlu menjalankan ini:

npx create-react-app counter
cd counter
npm start

Setelah instalasi, kita harus memiliki ini.

gunakanReducer

const [state, dispatch] = useReducer(reducer, initialArg, init);

UseReducer mengembalikan array dengan elemen pertama adalah status dan elemen kedua adalah fungsi pengiriman yang akan memanggil useReducer.

Untuk membangun aplikasi penghitung, kita memerlukan empat file: App.js utama untuk merender komponen kita; Counter.js untuk aplikasi counter kami; Reducer.js di mana kita akan mengelola status aplikasi menggunakan logika useReducer; dan Styles.css kami. Timbul pertanyaan: Apa yang kita lakukan? Bagaimana kita mengelola negara? Manfaat apa yang akan diberikan dibandingkan useState? Dan pertanyaannya terus berlanjut. Saya akan menjawab semua pertanyaan ini di artikel ini.

Pemutaran Ulang Sesi Sumber Terbuka

"OpenReplay" adalah rangkaian pemutaran ulang sesi bersumber terbuka yang memungkinkan Anda melihat apa yang dilakukan pengguna di aplikasi web Anda, sehingga membantu Anda memecahkan masalah dengan lebih cepat. OpenReplay dihosting sendiri untuk kontrol penuh atas data Anda.

Mulailah menikmati pengalaman debugging Anda — mulai menggunakan OpenReplay secara gratis.

Aplikasi Penghitung

Inilah cara kita memulainya.

const [count, dispatch] = useReducer(reducer, 0);

Alih-alih penyetel di useState, kami menggunakan dispatch. 'Pengiriman' di sini memiliki arti harfiah, lebih seperti Anda ingin mengirim sesuatu: Anda bisa mengatakan 'kirim tindakan'. Kami akan memprosesnya dengan fungsi peredam. Seperti yang bisa kita lihat di atas, kita mempunyai status 0. Mari mulai membangun aplikasi penghitung.

//counter.js
import React, { useReducer } from "react";
import reducer from "./Reducer";

function Counter() {
  const [count, dispatch] = useReducer(reducer, 0);

  return (
    <div className="container">
      <div className="card">
        <h1>Counter Application</h1>
        <h3>{count}</h3>
        <div>
          <button className="btn1" onClick={() => dispatch("increment")}>
            increment
          </button>

          <button className="btn2" onClick={() => dispatch("decrement")}>
            decrement
          </button>

          <button className="btn3" onClick={() => dispatch("reset")}>
            Reset
          </button>
        </div>
      </div>
    </div>
  );
}

export default Counter;

Kami juga punya:

//reducer.js

const reducer = (state, action) => {
  if (action === "increment") {
    return state + 1;
  } else if (action === "decrement") {
    return state - 1;
  } else if (action === "reset") {
    return 0;
  } else {
    throw new Error();
  }
};

export default reducer;

Dan penataan:

//styles.css

.container {
  display: flex;
  align-items: center;
  justify-content: center;
}

h3 {
  display: flex;
  align-items: center;
  justify-content: center;
}

.btn1 {
  background-color: blue;
  margin: 20px;
  color: beige;
}

.btn2 {
  background-color: red;
  margin: 20px;
  color: beige
}

.btn3 {
  background-color: green;
  margin: 20px;
  color: beige
}

Terakhir, file App utama kita.

//App.js

import React from "react";
import "./styles.css";
import Counter from "./Counter";

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

Kode di atas menunjukkan aplikasi penghitung yang statusnya dikelola oleh hook useReducer. Sebuah counter tidak mengajarkan banyak tentang manajemen negara yang kompleks, tapi kemudian saya akan menjelaskan logika yang digunakan di atas. Peredam menerima status kita dan tindakan yang dikirim. Di Reducer.js, fungsi peredam mengambil status kita, dan tindakan dikirim, lalu kita menggunakan pernyataan kondisional kita. Kami memiliki if-else kami dan lulus di action.type kami. Kami meneruskan increment, decrement, dan reset ke fungsi onclick di BEJ.

Kami sekarang dapat menguji aplikasi kami apakah ini berfungsi dengan baik. Awalnya kami memiliki:

Setelah beberapa peningkatan, kita mendapatkan:

Di sinilah kita mulai melihat useReducer menyinari kita. Kami mungkin tidak menyadari bahwa kami telah sepenuhnya melepaskan logika pembaruan status kami dari komponen kami. Kami sekarang memetakan tindakan untuk menyatakan transisi, dan sekarang kami dapat memisahkan bagaimana status diperbarui dari tindakan yang terjadi. (Kita akan mendalami manfaat praktisnya nanti.) Untuk saat ini, mari tambahkan fitur yang lebih kompleks ke aplikasi kita untuk menjelaskan dengan lebih baik betapa nyamannya useReducer.

Daripada hanya menambah dan mengurangi sebesar 1, mari kita buat penggeser di mana pengguna dapat memilih nilai yang ingin ditambah atau dikurangi mulai dari 1 hingga 100.

import React, { useState } from "react";

function Slider({ onchange, min, max }) {
  const [value, setvalue] = useState(1);

  return (
    <div className="slide">
      {value}
      <input
        type="range"
        min={min}
        max={max}
        value={value}
        onChange={(e) => {
          const value = Number(e.target.value);
          onchange(value);
          setvalue(value);
        }}
      />
    </div>
  );
}

export default Slider;

Kita perlu mengimpor ini ke Counter.js agar dapat dirender di browser. Kita juga akan meneruskan props min, max, dan onchange yang memberinya nilai.

import Slide from "./Slide";

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0, step: 1 });

  return (
    <div className='container'>
        <div className='card'>
            <h1>Counter Application</h1>
            <h3>{state.count}</h3>
            <div >
                <button className='btn1' onClick={() => dispatch('increment')}>increment</button>
                <button className='btn2' onClick={() => dispatch('decrement')}>decrement</button>
                <button className='btn3' onClick={() => dispatch('reset')}>Reset</button>
            </div>
            <div>
                <Slide
                    min={1}
                    max={100}
                    onchange={()=>({})}
                />
            </div>
        </div>
    </div>
  );
}

Inilah yang kami dapatkan.

Sekarang kita bisa mendapatkan nilai penggeser dari prop onChange. Ini memungkinkan kita memutuskan seberapa banyak kita dapat menambah dan mengurangi nilainya. Kita perlu membuat beberapa perubahan untuk mengelola bagian status pada nilai penggeser kita dan mengaktifkan penggeser untuk menentukan apa yang akan kita tambah atau kurangi.

Mari jadikan status kita sebagai objek: dengan demikian, setiap bagian status baru yang perlu dikelola oleh Reducer kita dapat dijadikan properti pada objek tersebut. Pertama, kita ubah keadaan awal kita menjadi sebuah objek.

const [state, dispatch] = useReducer(reducer, { count: 0, move: 1 });

Negara kita adalah sebuah objek. Kita perlu memperbarui peredam untuk mengembalikan objek dengan dua properti.

const reducer = (state, action) => {
  if (action === "increment") {
    return {
      count: state.count + 1,
      move: state.move,
    };
  } else if (action === "decrement") {
    return {
      count: state.count - 1,
      move: state.move,
    };
  } else if (action === "reset") {
    return {
      count: 0,
      move: state.move,
    };
  } else {
    throw new Error();
  }
};
export default reducer;

Kembali ke konter, kita perlu meneruskan status ke JSX.

<h3>{state.count}</h3>

Ini berfungsi dengan baik, tetapi alih-alih status kita menjadi bilangan bulat, kita sekarang memilikinya sebagai objek, memungkinkan kita meneruskan properti lainnya. Sekarang pertanyaannya muncul: apa yang ingin Anda kirimkan di onChange untuk memperbarui status peredam kami? Hingga saat ini, kami telah dapat mengirimkan jenis tindakan yang terjadi (penambahan, pengurangan, atau penyetelan ulang). Itu berhasil dengan baik, namun kini kami menghadapi keterbatasannya. Selain action type, diperlukan lebih banyak data. Secara khusus, kita perlu meneruskan nilai slide untuk menambahkannya ke nilai status dan memperbarui status. Daripada tindakan kita diteruskan sebagai string, mari kita ubah ke objek dengan properti type. Dengan cara ini, kami masih dapat mengirimkan berdasarkan jenis tindakan. Kita akan dapat meneruskan nilai penggeser dan data lainnya sebagai properti di objek tindakan. Kita dapat menuju ke prop onChange dan segera menyelesaikannya.

<Slide
  min={1}
  max={100}
  onchange={(value) =>
    dispatch({
      type: "stepUpdate",
      step: value,
    })
  }
/>;

Ada tiga perubahan yang perlu kita lakukan pada Reducer kita:

  • Kita perlu memperbarui kenaikan dan penurunan untuk menyesuaikan hitungan berdasarkan properti langkah dan bukan hanya dengan 1. Kita melakukan ini dengan memperbaruinya dengan move apa pun.
  • Kita perlu memperhitungkan jenis tindakan baru kita moveUpdate dengan menambahkan kasus di peredam kita
  • Kita perlu mengubah action menjadi objek dan bukan string dengan meneruskan properti type ke case baru kita saja.

Mari kita lakukan perbaikan cepat tersebut.

//Reducer.js

const reducer = (state, action) => {
  if (action === "increment") {
    return {
      count: state.count + state.move,
      move: state.move,
    };
  } else if (action === "decrement") {
    return {
      count: state.count - state.move,
      move: state.move,
    };
  } else if (action === "reset") {
    return {
      count: 0,
      move: state.move,
    };
  } else if (action.type === "moveUpdate") {
    return {
      count: state.count,
      move: action.move,
    };
  } else {
    throw new Error();
  }
};

export default reducer;

Sekarang kita dapat memperbarui nilai hitungan menggunakan penggeser — misalnya, kenaikan dari nol terlebih dahulu sebesar 31, lalu sebesar 48.

Kesimpulan

Kita telah sampai pada akhir artikel ini, tetapi saya perlu menjelaskan sesuatu yang sangat penting. Kami telah melihat manfaat luar biasa dan kuat dari useReducer yang mungkin Anda lewatkan: fungsi peredam meneruskan status saat ini sebagai argumen pertama. Oleh karena itu, mudah untuk memperbarui satu bagian negara bagian bergantung pada nilai bagian negara bagian lainnya. Untuk melakukan ini, Anda perlu menggunakan kait useReducer, bukan useState. Dalam contoh kita, kita bisa melihat ini ketika memperbarui count berdasarkan nilai `move '.

Artikel lainnya dari OpenReplay Blog

Formulir yang mengaktifkan suara di React with Speechly

Pelajari cara mengisi formulir dengan berbicara menggunakan React dan Speechly

4 Mei 2022 · 4 menit membaca

Awalnya diterbitkan di blog.openreplay.com pada 5 Mei 2022.