Membangun solusi manajemen status untuk Editor Alat Kreatif

Nov 28 2022
Pendahuluan Dalam artikel ini, kami akan membagikan beberapa wawasan kami (dengan sedikit pendapat) dalam merancang dan membangun solusi manajemen keadaan yang dapat diskalakan dalam konteks editor alat kreatif dengan React, Immer, dan Recoil sebagai dasar pendekatan kami. Untuk mengilustrasikan pendekatan kami dengan lebih baik, kami akan menyertakan beberapa contoh kode dan prototipe kecil.

Pendahuluan

Dalam artikel ini, kami akan membagikan beberapa wawasan kami (dengan sedikit pendapat) dalam merancang dan membangun solusi manajemen keadaan yang dapat diskalakan dalam konteks editor alat kreatif dengan React, Immer , dan Recoil sebagai dasar pendekatan kami.

Untuk mengilustrasikan pendekatan kami dengan lebih baik, kami akan menyertakan beberapa contoh kode dan prototipe kecil.

Kami telah menggunakan pengetahuan ini dalam beberapa proyek berbeda, memungkinkan kami untuk dengan mudah keluar dari beberapa jebakan yang paling umum.

Status aplikasi vs status desain

Salah satu perbedaan utama yang dapat kami buat dalam jenis aplikasi ini adalah status Aplikasi vs status Desain.

Keadaan desain

Menjelaskan konten yang dibuat pengguna, misalnya: teks (font, ukuran, warna, konten), gambar, elemen yang dikelompokkan, elemen yang terhubung, dll.

Status desain berubah setiap kali desain berubah secara konseptual, tetapi tidak saat pengguna melakukan tindakan yang tidak memengaruhi desain.

Beberapa contoh tindakan yang memengaruhi status desain:

  • Pindahkan elemen
  • Mengubah properti teks (warna, ukuran, font)
  • Elemen grup

Menentukan status aplikasi saat ini, tidak termasuk desain. Status aplikasi berubah saat pengguna berinteraksi dengan aplikasi dan menu mereka.

Beberapa contoh:

  • Pilih elemen
  • Buka dialog untuk mengedit properti elemen
  • Tampilkan menu klik kanan
  • Konfirmasi tindakan

Setiap jenis negara memiliki kekhasan masing-masing, yang tidak berlaku untuk yang lain, dan akan menyebabkan implementasi kita menjadi lebih kompleks jika tetap bersama.

Sebagai contoh:

  • Saat menyimpan desain, hanya bagian dari status ini yang disimpan.
  • Urungkan/ulangi hanya berlaku untuk keadaan desain. Aplikasi harus dapat bekerja dengan ketidakkonsistenan kecil antara desain dan status aplikasi, misalnya, saat elemen yang dipilih tidak lagi ada dalam desain karena dibatalkan.
  • Saat memuat desain, status desain hanya diatur dengan desain, sedangkan status aplikasi sebagian besar diinisialisasi dengan nilai default.

Status aplikasi

Kapan pun kita bisa, kita harus mengutamakan keadaan lokal daripada keadaan global, tidak terkecuali keadaan aplikasi.

Menganalisis kode dan alirannya menjadi lebih mudah ketika kita menggunakan keadaan lokal, komponen harus secara eksplisit meneruskan data satu sama lain dan interaksinya eksplisit, tidak ada efek penggunaan "jauh tersembunyi" yang harus kita cari secara manual.

Keadaan desain

Saat mendefinisikan keadaan desain, kita harus memiliki pertimbangan berikut:

  • Mampu mendapatkan dan mengatur seluruh keadaan sehingga kita dapat dengan mudah mengimplementasikan:
    – Memuat dan menyimpan desain
    – Membatalkan/mengulangi
  • Hindari merender semua elemen ketika hanya beberapa di antaranya yang berubah

Salah satu cara termudah untuk mengimplementasikan undo/redo dalam aplikasi React adalah menggunakan I mmer untuk membuat tambalan modifikasi.

Immer adalah library JS yang memungkinkan kita untuk menulis modifikasi data dalam konteks yang tidak dapat diubah (misalnya status React) dengan "cara yang dapat diubah".

Fitur lain dari Immer adalah pembuatan tambalan do dan undo dari suatu modifikasi, ini memungkinkan kita untuk menyimpan cara menjalankan kembali perubahan yang kita buat dan cara kembali ke status pratinjau.

Setelah setiap perubahan status, kita harus menyimpan patch do dan undo, dan menggunakannya saat pengguna memicu undo/redo.

Mengapa kita perlu mendapatkan dan mengatur seluruh keadaan pada waktu yang bersamaan?

Alternatifnya adalah tidak menggabungkannya, ini sepertinya bukan masalah besar untuk memuat dan menyimpan, kita hanya perlu mendapatkan/mengatur semua bagian status yang berbeda.

Namun menjadi masalah ketika kita harus mengimplementasikan undo/redo. Untuk setiap bagian keadaan, kita harus menyimpan tambalan yang dihasilkan, dengan metadata yang menunjukkan untuk bagian keadaan mana, dan membacanya saat undo dipicu sehingga kita dapat mengubah bagian keadaan yang benar.

Selain itu, karena tindakan pengguna dapat memodifikasi beberapa bagian status sebagai satu operasi, kami harus tetap melacak tambalan mana yang termasuk dalam operasi yang sama sehingga kami dapat membatalkan dan mengulanginya pada waktu yang sama.

Menggunakan satu negara bagian akan menyelesaikan semua hal ini

  • Tidak ada tindakan yang mengubah banyak status
  • Semua tambalan berlaku untuk negara bagian, bukan untuk beberapa negara bagian terdistribusi.

Cara yang lebih mudah untuk memenuhi pilihan desain ini adalah dengan menyimpan seluruh status desain di tempat yang sama. Itu akan membuat kami berpikir seperti useState<DesignState>(defaultState), seperti yang mungkin Anda duga, ini menyebabkan kami gagal dalam pertimbangan "merender sebagian besar aplikasi" kami:

Tidak merender sebagian besar aplikasi saat desain berubah

Untuk mengatasi ini, kami biasanya menggunakan Recoil, perpustakaan manajemen status untuk React.

Recoil memiliki dua konsep utama : atom dan penyeleksi.

Atom : satuan keadaan, yang dapat digunakan dengan cara yang mirip dengan useState, tetapi secara global, misalnya

Sebagai useStateimplementasinya, pada kode di atas, semua DesignElements akan merender setiap kali ada elemen (atau bagian mana pun dari status) yang berubah. Untuk mengatasi ini, kita dapat menggunakan penyeleksi.

Selektor : fungsi yang membuat proyeksi dari atom atau selektor lainnya. Ketika sebuah komponen React menggunakan pemilih, ia hanya akan merender ulang ( dengan beberapa peringatan) ketika hasil dari pemilih berubah.

Recoil juga memungkinkan kita menerima argumen dalam fungsi yang mendefinisikan pemilih, jenis penyeleksi tersebut disebut selectorFamily. Kita bisa menggunakan ini untuk membuat selectorFamily yang menerima elementId dan memberi kita elemen.

Saat elemen dimodifikasi, kode di atas hanya memicu pembaruan ke DesignElement yang cocok dan tidak merender semua elemen atau komponen Desain.

Pengamat yang penuh perhatian mungkin melihat bahwa komponen Desain akan dirender setiap kali komponen ditambahkan atau dihapus, memicu rendering ulang semua DesignElements. Jika ini menyebabkan masalah kinerja untuk kasus penggunaan tertentu, kita dapat membungkus komponen DesignElement kita dalam file React.memo.

Tetapkan negara bagian

Karena kami ingin set kami diterapkan ke DesignState tingkat atas (untuk menyederhanakan undo/redo), kami dapat membuat recoil callback untuk merangkum logika modifikasi kami dan membatalkan/mengulangi pembuatan tambalan.

Contoh minimal dapat ditemukan di Codesanbox ini.

Penutupan

Dalam postingan blog ini, kami membagikan apa yang menjadi pendorong utama saat merancang manajemen status dalam konteks editor alat kreatif, dan penerapan langsung kami yang memuaskan mereka.

Jika Anda membacanya sampai di sini, saya ingin tahu pendapat Anda. Anda dapat menghubungi saya di sini .

Di Zeppelin Labs, kami membantu para pendiri dan perusahaan berkembang bereksperimen dan membangun produk digital berbeda yang mendorong pertumbuhan. Anda dapat menemukan kami di sini . Atau di sini . Atau di sini .

Jika Anda ingin bergabung dengan tim kami, kirim email kepada kami di [email protected]

Ingin bermitra? email kami di [email protected]

Berlangganan Newsletter kami di sini .