Menggunakan Immer untuk Mengelola Status Aplikasi Bereaksi

Negara digunakan untuk mengatur pemantauan data dari Bereaksi aplikasi. Negara berubah saat pengguna berinteraksi dengan aplikasi. Ketika pengguna melakukan beberapa tindakan, kita perlu memperbarui keadaan, yang merupakan kumpulan data berdasarkan apa yang pengguna lihat di layar terbentuk. Perbarui keadaan Bereaksi aplikasi menggunakan metode setState .



Karena negara tidak boleh diperbarui secara langsung (dalam Bereaksi, negara harus tidak berubah), dengan kerumitan struktur negara, bekerja dengan mereka berubah menjadi tugas yang sangat sepele. Yakni, menjadi sulit bagi programmer untuk bernavigasi di negara bagian dan menggunakan datanya dalam aplikasi.

Dalam situasi seperti itu, Anda dapat menggunakan perpustakaan Immer. Penggunaannya dalam React-aplikasi dikhususkan untuk materi, terjemahan yang kami terbitkan hari ini.

Dasar-dasar Penggunaan Immer dalam Aplikasi Bereaksi


Saat menggunakan Immer, struktur keadaan aplikasi Bereaksi dapat disederhanakan, yang berarti akan lebih mudah digunakan. Immer menggunakan konsep yang disebut "draft". "Draf" dapat diambil sebagai salinan negara, tetapi bukan negara itu sendiri.

Immer, seolah-olah, menyalin keadaan dengan "menekan" tombol CMD + C, kemudian, menggunakan kunci CMD + V, memasukkan apa yang disalin ke tempat di mana data yang disalin dapat dilihat tanpa mengganggu bahan aslinya. Mengubah data yang termasuk dalam negara bagian dilakukan dalam "konsep", setelah itu, berdasarkan perubahan yang dibuat pada "konsep", keadaan aplikasi saat ini diperbarui.

Misalkan kondisi aplikasi Anda terlihat seperti ini:

this.state = {   name: 'Kunle',   age: 30,   city: 'Lagos',   country: 'Nigeria' } 

Ini adalah data pengguna. Pengguna ini, ternyata, sedang merayakan ulang tahunnya yang ke-31. Ini berarti bahwa kita perlu memperbarui umurnya (properti age ). Jika Anda menggunakan Immer untuk menyelesaikan masalah ini, salinan dari status ini akan dibuat terlebih dahulu.

Sekarang bayangkan sebuah salinan kekayaan dibuat, itu diserahkan kepada kurir, dan dia mengirimkan salinan ini kepada Kunle. Ini berarti bahwa sekarang ada dua salinan negara. Salah satunya adalah keadaan aplikasi saat ini, dan yang kedua adalah salinan "kasar" yang ditransfer ke pengguna. Pengguna, mengedit "draft", mengubah usianya menjadi 31. Setelah itu, kurir kembali dengan dokumen yang diubah dan memberikan "draft" ke aplikasi. Di sana, perbandingan dua versi dokumen dilakukan, dan hanya perubahan yang berkaitan dengan usia pengguna yang dibuat dengan keadaan aplikasi saat ini, karena tidak ada lagi yang berubah dalam "konsep".

Skema kerja semacam itu tidak melanggar gagasan kekebalan negara - keadaan saat ini tidak diperbarui secara langsung. Secara umum, kita dapat mengatakan bahwa penggunaan Immer hanya membantu meningkatkan kegunaan keadaan kekebalan tubuh.

Contoh No. 1: lampu lalu lintas


Mari kita lihat contoh aplikasi yang menggunakan Immer. Misalkan Anda sedang mengembangkan aplikasi lampu lalu lintas. Dalam aplikasi ini Anda dapat mencoba menggunakan Immer.

Berikut tampilan layar aplikasi ini di salah satu momen operasinya.


Aplikasi lampu lalu lintas

Di sini Anda dapat menemukan kode proyek.

Di sini akan terlihat seperti apa komponennya, mengingat bahwa proyek tersebut menggunakan Immer.

 const {produce} = immer class App extends React.Component {  state = {    red: 'red',    yellow: 'black',    green: 'black',    next: "yellow"  }  componentDidMount() {    this.interval = setInterval(() => this.changeHandle(), 3000);  }   componentWillUnmount() {    clearInterval(this.interval);  }  handleRedLight = () => {    this.setState(      produce(draft => {        draft.red = 'red';        draft.yellow = 'black';        draft.green = 'black';        draft.next = 'yellow'      })    )  }   handleYellowLight = () => {    this.setState(      produce(draft => {        draft.red = 'black';        draft.yellow = 'yellow';        draft.green = 'black';        draft.next = 'green'      })    )  }   handleGreenLight = () => {    this.setState(      produce(draft => {        draft.red = 'black';        draft.yellow = 'black';        draft.green = 'green';        draft.next = 'red'      })    )  }  changeHandle = () => {    if (this.state.next === 'yellow') {      this.handleYellowLight()    } else if (this.state.next === 'green') {      this.handleGreenLight()    } else {      this.handleRedLight()    }     }  render() {    return (      <div className="box">        <div className="circle" style={{backgroundColor: this.state.red}}></div>        <div className="circle" style={{backgroundColor: this.state.yellow}}></div>        <div className="circle" style={{backgroundColor: this.state.green}}></div>      </div>  ); } }; 

Produce adalah fitur standar yang diimpor dari Immer. Kami meneruskannya, sebagai nilai, ke metode setState() . Fungsi produce mengambil fungsi yang, sebagai argumen, mengambil draft . Dalam fungsi ini kita dapat mengedit status "draft", membawanya ke bentuk yang seharusnya berbentuk nyata.

Jika semua ini tampaknya terlalu rumit bagi Anda - berikut adalah pendekatan lain untuk menulis kode yang menyelesaikan tugas yang sama dengan kode di atas. Pertama, buat fungsi:

 const handleLight = (state) => {  return produce(state, (draft) => {    draft.red = 'black';    draft.yellow = 'black';    draft.green = 'green';    draft.next = 'red'  }); } 

Untuk fungsi produce , kami, sebagai argumen, melewati status aplikasi saat ini dan fungsi lain yang menggunakan draft argumen. Sekarang mari kita manfaatkan semua ini dalam komponen:

 handleGreenLight = () => {  const nextState = handleLight(this.state)  this.setState(nextState) } 

Contoh 2: daftar belanja


Jika Anda telah bekerja dengan Bereaksi selama beberapa waktu, maka Anda seharusnya tidak terkejut dengan sintaksis penyebaran . Saat menggunakan Immer, Anda tidak perlu menggunakan desain serupa. Secara khusus, ketika bekerja dengan array yang terdapat dalam keadaan.

Kami akan terus mengeksplorasi kemungkinan Immer, membuat aplikasi yang mengimplementasikan daftar belanja.


Daftar belanja

Di sini Anda dapat bereksperimen dengannya.

Berikut adalah komponen yang kami kerjakan.

 class App extends React.Component {  constructor(props) {      super(props)           this.state = {        item: "",        price: 0,        list: [          { id: 1, name: "Cereals", price: 12 },          { id: 2, name: "Rice", price: 10 }        ]      }    }    handleInputChange = e => {      this.setState(      produce(draft => {        draft[event.target.name] = event.target.value      }))    }    handleSubmit = (e) => {      e.preventDefault()      const newItem = {        id: uuid.v4(),        name: this.state.name,        price: this.state.price      }      this.setState(        produce(draft => {          draft.list = draft.list.concat(newItem)        })      )    };  render() {    return (      <React.Fragment>        <section className="section">          <div className="box">            <form onSubmit={this.handleSubmit}>              <h2>Create your shopping list</h2>              <div>                <input                  type="text"                  placeholder="Item's Name"                  onChange={this.handleInputChange}                  name="name"                  className="input"                  />              </div>              <div>                <input                  type="number"                  placeholder="Item's Price"                  onChange={this.handleInputChange}                  name="price"                  className="input"                  />              </div>              <button className="button is-grey">Submit</button>            </form>          </div>                   <div className="box">            {              this.state.list.length ? (                this.state.list.map(item => (                  <ul>                    <li key={item.id}>                      <p>{item.name}</p>                      <p>${item.price}</p>                    </li>                    <hr />                  </ul>                ))              ) : <p>Your list is empty</p>            }          </div>        </section>      </React.Fragment>    )  } } ReactDOM.render(  <App />,  document.getElementById('root') ); 

Saat menambahkan catatan belanja baru ke daftar, kita perlu memperbarui keadaan komponen di mana, dalam array list , elemen baru harus disimpan. Untuk memperbarui item list menggunakan metode setState() , setState() memerlukan kode berikut:

 handleSubmit = (e) => {  e.preventDefault()  const newItem = {    id: uuid.v4(),    name: this.state.name,    price: this.state.price  }  this.setState({ list: [...this.state.list, newItem] }) }; 

Jika selama pengoperasian aplikasi Anda perlu memperbarui banyak elemen state - sintaks penyebaran harus sering digunakan. Status baru diperoleh dengan menggabungkan apa yang sudah ada dalam status dengan data baru. Ketika jumlah perubahan bertambah, pekerjaan menjadi lebih rumit. Jika menggunakan Immer - hal-hal seperti itu tidak menyebabkan kesulitan. Anda dapat memverifikasi ini dengan melihat kode contoh di awal bagian ini.

Tetapi bagaimana jika kita ingin menambahkan fungsi ke proyek itu, dalam bentuk panggilan balik, akan dipanggil setelah memperbarui negara? Misalnya, ini mungkin diperlukan jika Anda perlu menghitung jumlah entri dalam daftar atau total biaya semua pembelian yang direncanakan.

Di sini Anda dapat melihat kode aplikasi, yang sekarang akan kami analisis. Antarmukanya ditunjukkan di bawah ini.


Aplikasi dengan fungsi menghitung total biaya pembelian yang direncanakan

Jadi, anggaplah kita ingin menghitung nilai total pembelian yang direncanakan. Mari kita mulai dengan membuat mekanisme pembaruan status. Mekanisme ini diwakili oleh fungsi handleSubmit :

 handleSubmit = (e) => {  e.preventDefault()  const newItem = {    id: uuid.v4(),    name: this.state.name,    price: this.state.price  }   this.setState(    produce(draft => {      draft.list = draft.list.concat(newItem)    }), () => {      this.calculateAmount(this.state.list)    }  ) }; 

Dalam fungsi handleSubmit pertama-tama kita membuat objek berdasarkan data yang dimasukkan oleh pengguna. Referensi ke objek ditulis ke newItem konstan. Untuk membentuk keadaan baru aplikasi, metode .concat() digunakan. Metode ini, dipanggil pada array, mengembalikan array baru, yang mencakup elemen array asli, serta elemen baru. Array baru ditulis ke draft.list . Setelah itu, Immer dapat memperbarui status aplikasi.

Callback, fungsi calculateAmount , dipanggil setelah pembaruan keadaan. Penting untuk dicatat bahwa fungsi ini menggunakan versi negara yang diperbarui.

Fungsi calculateAmount akan terlihat seperti ini:

 calculateAmount = (list) => {  let total = 0;    for (let i = 0; i < list.length; i++) {      total += parseInt(list[i].price, 10)    }  this.setState(    produce(draft => {      draft.totalAmount = total    })  ) } 

Kait lebih dekat


Use-immer adalah pengait yang memungkinkan pengembang mengontrol keadaan aplikasi Bereaksi. Mari kita lihat bagaimana kait ini bekerja dengan mengimplementasikan aplikasi penghitung klasik berdasarkan:

 import React from "react"; import {useImmer} from "use-immer"; const Counter = () => {  const [count, updateCounter] = useImmer({    value: 0  });  function increment() {    updateCounter(draft => {      draft.value = draft.value +1;    });  }  return (    <div>      <h1>        Counter {count.value}      </h1>      <br />      <button onClick={increment}>Increment</button>    </div>  ); } export default Counter; 

Fungsi useImmer sangat mirip dengan metode useState . Fungsi mengembalikan status dan fungsi yang memperbarui status. Saat komponen dimuat pertama kali, konten negara (dalam hal ini, properti count ) sesuai dengan nilai yang diteruskan ke useImmer . Menggunakan fungsi yang dikembalikan untuk memperbarui status memungkinkan kami untuk membuat fungsi kenaikan yang menambah nilai properti status count .

Dan di sini adalah kode yang menggunakan hook untuk Immer, mengingatkan kita pada useReducer :

 import React, { useRef } from "react"; import {useImmerReducer } from "use-immer"; import uuidv4 from "uuid/v4" const initialState = []; const reducer = (draft, action) => {  switch (action.type) {    case "ADD_ITEM":      draft.push(action.item);      return;    case "CLEAR_LIST":      return initialState;    default:      return draft;  } } const Todo = () => {  const inputEl = useRef(null);  const [state, dispatch] = useImmerReducer(reducer, initialState);   const handleSubmit = (e) => {    e.preventDefault()    const newItem = {      id: uuidv4(),      text: inputEl.current.value    };    dispatch({ type: "ADD_ITEM", item: newItem });    inputEl.current.value = "";    inputEl.current.focus();  }   const handleClear = () => {    dispatch({ type: 'CLEAR_LIST' })  }   return (    <div className='App'>      <header className='App-header'>        <ul>          {state.map(todo => {            return <li key={todo.id}>{todo.text}</li>;          })}        </ul>        <form onSubmit={handleSubmit}>          <input type='text' ref={inputEl} />          <button            type='submit'          >            Add Todo          </button>        </form>        <button          onClick={handleClear}        >          Clear Todos        </button>      </header>    </div>  ); } export default Todo; 

Fungsi useImmerReducer menerima fungsi useImmerReducer dan status awal. Ini mengembalikan fungsi negara dan dispatch . Setelah itu, Anda dapat melewati negara untuk menampilkan elemen di dalamnya. Tindakan pengiriman menggunakan fungsi dispatch dilakukan ketika item baru ditambahkan ke daftar tugas dan ketika daftar dihapus. Tindakan yang akan dikirim ditetapkan jenis berdasarkan keputusan yang dibuat dalam fungsi peredam tentang apa yang sebenarnya perlu dilakukan untuk memproses tindakan tertentu.

Dalam peredam, kami menggunakan, seperti sebelumnya, entitas draft , bukan state . Berkat ini, kami memiliki cara mudah untuk mengontrol status aplikasi.

Kode yang digunakan dalam contoh sebelumnya dapat ditemukan di sini .

Ringkasan


Pada artikel ini, kita berbicara tentang Immer, perpustakaan yang menyederhanakan pengelolaan keadaan aplikasi Bereaksi. Penulis artikel percaya bahwa setiap orang yang tertarik pada perpustakaan ini dapat menggunakan Immer dalam aplikasi baru mereka atau secara perlahan memperkenalkannya ke dalam salah satu proyek saat ini.

Berikut adalah bahan di mana Anda dapat menemukan beberapa detail tentang Immer.

Pembaca yang budiman! Apakah Anda berencana menggunakan Immer?

Source: https://habr.com/ru/post/id463337/


All Articles