Redux: Apa kerugian menyimpan semua keadaan Anda dalam satu atom yang tidak bisa diubah?

Dibuat pada 10 Feb 2016  ·  91Komentar  ·  Sumber: reduxjs/redux

Saya mengerti bahwa ini adalah prinsip yang mendasari semua redux, dan ia hadir dengan semua manfaat luar biasa yang cukup terkenal sekarang.

Namun, saya merasa bahwa satu hal yang kurang dari redux, adalah ia tidak secara terbuka menjelaskan kerugian konseptual dari penggunaan arsitektur ini. Mungkin ini adalah pilihan yang baik karena Anda ingin orang tidak menghindar karena hal-hal negatif.

Saya hanya ingin tahu karena ini berlaku tidak hanya untuk redux, tetapi dalam beberapa kapasitas untuk hal-hal lain seperti Om , datomic dan pembicaraan tentang mengubah database ke luar . Saya suka redux, saya suka Om, saya tertarik dengan datomic, dan saya sangat menyukai pembicaraan itu.

Tetapi untuk semua pencarian yang telah saya lakukan, sulit untuk menemukan orang-orang yang mengkritik satu toko yang tidak dapat diubah itu. Ini adalah sebuah contoh, tetapi sepertinya lebih banyak masalah dengan verbositas redux daripada dengan arsitektur sebenarnya.

Satu-satunya hal yang dapat saya pikirkan adalah mungkin dibutuhkan lebih banyak memori untuk menyimpan salinan negara Anda, atau sedikit lebih sulit untuk melakukan protoype dengan cepat dengan redux.

Karena kalian mungkin lebih memikirkan hal ini daripada saya, dapatkah Anda membantu menjelaskan hal ini untuk saya?

discussion docs question

Komentar yang paling membantu

Redux pada dasarnya adalah sumber peristiwa di mana ada satu proyeksi untuk dikonsumsi.

Dalam sistem terdistribusi, umumnya ada satu log peristiwa (seperti Kafka), dan banyak konsumen yang dapat memproyeksikan / mengurangi log ini ke dalam beberapa database / penyimpanan yang di-host di server yang berbeda (biasanya, replika DB sebenarnya adalah peredam). Jadi di dunia terdistribusi, beban dan penggunaan memori ... didistribusikan, sedangkan di Redux jika Anda memiliki ratusan widget yang semuanya memiliki status lokalnya, semua ini berjalan dalam satu browser, dan setiap perubahan status memiliki beberapa overhead karena tidak dapat diubah pembaruan data.

Dalam kebanyakan kasus, overhead ini bukanlah masalah besar, namun saat memasang input teks ke dalam bentuk yang tidak terlalu bagus, dan mengetik cepat di perangkat seluler yang lambat, performanya tidak selalu cukup.

Merender status tersebut dari atas, menurut pengalaman saya, tidak nyaman dan juga tidak selalu berkinerja cukup (setidaknya dengan React yang mungkin bukan implementasi VDom tercepat). Redux menyelesaikan ini dengan connect tetapi tetap saja, seiring bertambahnya jumlah koneksi, ini bisa menjadi hambatan. Ada solusinya

Juga struktur data yang persisten seperti ImmutableJS tidak selalu menawarkan kinerja terbaik pada beberapa operasi, seperti menambahkan item pada indeks acak dalam daftar besar (lihat pengalaman saya membuat daftar besar di sini )

Redux menyertakan event log dan proyeksi karena nyaman dan baik untuk sebagian besar kasus penggunaan, tetapi dimungkinkan untuk mempertahankan log peristiwa di luar redux, dan memproyeksikannya ke 2 atau lebih toko redux, tambahkan semua penyimpanan redux ini ke bereaksi konteks di bawah kunci yang berbeda, dan memiliki lebih sedikit overhead dengan menentukan penyimpanan mana yang ingin kita sambungkan. Hal ini sangat mungkin, namun ini akan membuat api dan devtools lebih sulit untuk diterapkan karena sekarang Anda memerlukan perbedaan yang jelas antara penyimpanan dan log peristiwa.


Saya juga setuju dengan @jquense

Manfaat hidrasi yang mudah, snapshot, perjalanan waktu, dll hanya berfungsi jika tidak ada tempat lain yang dihuni negara penting. Dalam konteks React, ini berarti Anda perlu menyimpan status, yang merupakan bagian dari komponen di Store, atau kehilangan banyak manfaat. Jika Anda benar-benar ingin memasukkan semuanya ke dalam Redux, hal itu sering kali menjadi memberatkan dan bertele-tele, dan menambahkan tingkat tipuan yang mengganggu.

Memasang status apa pun ke toko Redux membutuhkan lebih banyak boilerplate. Arsitektur Elm mungkin menyelesaikan ini dengan cara yang lebih elegan tetapi juga membutuhkan banyak boilerplate.

Tetapi juga tidak mungkin atau tidak berhasil untuk membuat semua negara dikendalikan. Kadang-kadang kami menggunakan pustaka yang ada yang sulit untuk membangun antarmuka deklaratif. Beberapa keadaan juga sulit dipasang ke penyimpanan redux dengan cara yang efisien, termasuk:

  • Input teks
  • Posisi gulir
  • Ukuran area pandang
  • Posisi mouse
  • Posisi / pemilihan tanda sisipan
  • Canvas dataUrls
  • Keadaan tidak dapat diserialisasi
  • ...

Semua 91 komentar

Itu pertanyaan yang bagus. Saya akan mencoba menulis jawaban lengkap besok, tetapi saya ingin mendengar dari beberapa pengguna kami terlebih dahulu. Alangkah baiknya untuk merangkum diskusi ini sebagai halaman dokumen resmi nanti. Kami tidak melakukan ini pada awalnya karena kami tidak tahu kekurangannya.

Terima kasih banyak! Saya benar-benar ingin mendengar tentang ini.

Ngomong-ngomong, saya mendorong semua orang yang ingin berkontribusi dalam diskusi ini untuk juga memberikan gambaran tentang apa yang mereka bangun dengan Redux sehingga lebih mudah untuk memahami ruang lingkup proyek.

Ini semacam pertanyaan sulit proyek b / c seperti OM dan redux dan libs atom negara tunggal lainnya, secara aktif mengurangi kerugian. Tanpa batasan kekekalan, dan akses yang terkontrol dan terjaga keamanannya, atom status tunggal sama sekali tidak berbeda dengan melampirkan semua data Anda ke window (yang kelemahannya diketahui dengan baik)

Khusus untuk pendekatan Redux, kelemahan terbesar bagi kami adalah bahwa atom keadaan tunggal adalah semacam semua atau tidak sama sekali. Manfaat hidrasi yang mudah, snapshot, perjalanan waktu, dll hanya berfungsi jika _tidak ada tempat lain kehidupan negara yang penting. Dalam konteks React, ini berarti Anda perlu menyimpan status, yang merupakan bagian dari komponen di Store, atau kehilangan banyak manfaat. Jika Anda benar-benar ingin memasukkan semuanya ke dalam Redux, hal itu sering kali menjadi memberatkan dan bertele-tele, dan menambahkan tingkat tipuan yang mengganggu.

Namun, tidak satu pun dari kerugian ini yang menjadi penghalang bagi kami :)

Jadi, saya telah mengamati Redux, dan gaya arsitektur ini, untuk membuat model status permainan; Saya memiliki minat untuk membuat dunia simulasi gaya Civ, dan sejarah permainan papan yang direkam secara lengkap dengan lebih sederhana, dalam konteks browser, yang mungkin merupakan kasus penggunaan yang tidak biasa bagi sebagian orang, tetapi saya ragu ada orang yang ingin saya berhenti juga.

Dalam konteks itu, saya tertarik pada upaya untuk mengelola ukuran struktur data riwayat, untuk memindahkan bagian-bagiannya ke server atau disk untuk menyimpannya, memulihkan segmen tertentu, dll.

Hal yang saya perjuangkan, sebagai pengguna baru yang paling berusaha untuk mengatasi baik perubahan gaya pengkodean yang ekstrim (imho) di Redux, dan perubahan konseptual pada saat yang sama; itu tetap sedikit menakutkan bahkan sekarang, sebulan dan berubah setelah mencoba menyelami lebih dalam; Saya melihat ke https://github.com/ngrx/store selanjutnya untuk mendapatkan konsep tetapi dengan gaya / sintaks yang lebih akrab dan lebih banyak kerangka tersirat / disediakan lainnya.

Saya memahami bahwa bagi beberapa orang, kerangka adalah penopang; tetapi beberapa dari kita membutuhkan itu; hanya sedikit orang yang akan berada di puncak permainan mereka cukup untuk memiliki pendapat kuat yang berguna, jadi kerangka kerja lebih baik daripada meraba-raba dalam kegelapan, Anda tahu? Jadi itulah poin dari saya, programmer paruh baya level menengah yang baru mengenal konsep :)

Pada dasarnya, Redux dan video Anda mengajari saya cara melakukannya dalam javascript mentah, tetapi sebagai programmer yang kurang berpengalaman, saya masih tidak tahu bagaimana cara mengirimkan produk tanpa panduan lebih lanjut, jadi sampai saya melihat contoh hasil akhir itu, saya hanya berdiri di sekitar seperti:

Bukan salahmu, tapi masih masalah yang ingin saya bantu selesaikan :)

Saya pikir pertanyaan terbesar yang masih saya miliki saat ini adalah, ke mana item yang tidak dapat diserialkan seperti fungsi, instance, atau janji pergi? Saya bertanya-tanya tentang hal ini di Reactiflux malam itu dan tidak mendapat tanggapan yang baik. Juga baru saja melihat seseorang memposting http://stackoverflow.com/questions/35325195/should-i-store-function-references-in-redux-store .

Kasus penggunaan untuk beberapa toko (perlu diingat, ini adalah yang terbaik yang dapat saya pikirkan):

Aplikasi yang menggabungkan beberapa sub-aplikasi menjadi satu. Pikirkan sesuatu seperti My Yahoo atau produk halaman beranda lain yang dapat disesuaikan. Setiap widget perlu mempertahankan statusnya sendiri tanpa tumpang tindih di antara keduanya. Tim produk kemungkinan besar ditugaskan untuk setiap widget, jadi mereka mungkin tidak mengetahui pengaruh kode orang lain terhadap lingkungan.

Jika dikumpulkan, Anda mungkin dapat mencapai ini di Redux dengan melanggar beberapa aturan dan berhati-hati dalam menyebarkan penyimpanan tersebut pada sesuatu seperti konteks React. Tapi mungkin lebih mudah dengan kerangka kerja yang menangani banyak atom keadaan secara default.

@gaearon kami sedang membangun platform perdagangan. Saya sudah pernah menjelaskan kepada Anda mengapa satu toko tidak cocok untuk kita (setelah pertemuan React.js di Saint-Petersburg). Saya akan mencoba menjelaskannya lagi secara detail (dalam posting blog di medium?) Tetapi saya mungkin memerlukan bantuan karena kemampuan bahasa Inggris saya :) Bolehkah saya mengirimkannya kepada Anda atau orang lain di sini untuk ditinjau di Twitter langsung pesan kapan itu akan dilakukan? Saya tidak dapat menyebutkan tanggal pastinya tetapi saya akan mencoba untuk menulis posting ini segera (kemungkinan besar akhir bulan ini).

Dan ya kami masih menggunakan Redux dengan banyak penyimpanan dengan melanggar beberapa aturan dari dokumen seperti yang dikatakan @timdorr (sebagai react-redux dengan nyaman jika kami membutuhkan data dari berbagai toko seperti apa adanya dalam kasus satu toko)

Redux pada dasarnya adalah sumber peristiwa di mana ada satu proyeksi untuk dikonsumsi.

Dalam sistem terdistribusi, umumnya ada satu log peristiwa (seperti Kafka), dan banyak konsumen yang dapat memproyeksikan / mengurangi log ini ke dalam beberapa database / penyimpanan yang di-host di server yang berbeda (biasanya, replika DB sebenarnya adalah peredam). Jadi di dunia terdistribusi, beban dan penggunaan memori ... didistribusikan, sedangkan di Redux jika Anda memiliki ratusan widget yang semuanya memiliki status lokalnya, semua ini berjalan dalam satu browser, dan setiap perubahan status memiliki beberapa overhead karena tidak dapat diubah pembaruan data.

Dalam kebanyakan kasus, overhead ini bukanlah masalah besar, namun saat memasang input teks ke dalam bentuk yang tidak terlalu bagus, dan mengetik cepat di perangkat seluler yang lambat, performanya tidak selalu cukup.

Merender status tersebut dari atas, menurut pengalaman saya, tidak nyaman dan juga tidak selalu berkinerja cukup (setidaknya dengan React yang mungkin bukan implementasi VDom tercepat). Redux menyelesaikan ini dengan connect tetapi tetap saja, seiring bertambahnya jumlah koneksi, ini bisa menjadi hambatan. Ada solusinya

Juga struktur data yang persisten seperti ImmutableJS tidak selalu menawarkan kinerja terbaik pada beberapa operasi, seperti menambahkan item pada indeks acak dalam daftar besar (lihat pengalaman saya membuat daftar besar di sini )

Redux menyertakan event log dan proyeksi karena nyaman dan baik untuk sebagian besar kasus penggunaan, tetapi dimungkinkan untuk mempertahankan log peristiwa di luar redux, dan memproyeksikannya ke 2 atau lebih toko redux, tambahkan semua penyimpanan redux ini ke bereaksi konteks di bawah kunci yang berbeda, dan memiliki lebih sedikit overhead dengan menentukan penyimpanan mana yang ingin kita sambungkan. Hal ini sangat mungkin, namun ini akan membuat api dan devtools lebih sulit untuk diterapkan karena sekarang Anda memerlukan perbedaan yang jelas antara penyimpanan dan log peristiwa.


Saya juga setuju dengan @jquense

Manfaat hidrasi yang mudah, snapshot, perjalanan waktu, dll hanya berfungsi jika tidak ada tempat lain yang dihuni negara penting. Dalam konteks React, ini berarti Anda perlu menyimpan status, yang merupakan bagian dari komponen di Store, atau kehilangan banyak manfaat. Jika Anda benar-benar ingin memasukkan semuanya ke dalam Redux, hal itu sering kali menjadi memberatkan dan bertele-tele, dan menambahkan tingkat tipuan yang mengganggu.

Memasang status apa pun ke toko Redux membutuhkan lebih banyak boilerplate. Arsitektur Elm mungkin menyelesaikan ini dengan cara yang lebih elegan tetapi juga membutuhkan banyak boilerplate.

Tetapi juga tidak mungkin atau tidak berhasil untuk membuat semua negara dikendalikan. Kadang-kadang kami menggunakan pustaka yang ada yang sulit untuk membangun antarmuka deklaratif. Beberapa keadaan juga sulit dipasang ke penyimpanan redux dengan cara yang efisien, termasuk:

  • Input teks
  • Posisi gulir
  • Ukuran area pandang
  • Posisi mouse
  • Posisi / pemilihan tanda sisipan
  • Canvas dataUrls
  • Keadaan tidak dapat diserialisasi
  • ...

Pertanyaan ini baru saja saya lihat di SO:

http://stackoverflow.com/questions/35328056/react-redux-should-all-component-states-be-kept-in-redux-store

Gema beberapa kebingungan yang pernah saya lihat tentang mengelola status UI, dan apakah status UI harus menjadi bagian dari komponen atau masuk ke store. # 1287 menawarkan jawaban yang bagus untuk pertanyaan ini, tetapi pada awalnya tidak begitu jelas dan dapat diperdebatkan.

Selain itu, ini bisa menjadi penghalang jika Anda mencoba menerapkan sesuatu seperti ini https://github.com/ericelliott/react-pure-component-starter di mana setiap komponen murni dan tidak memiliki suara dalam statusnya sendiri .

Saya merasa sulit untuk menggunakan pohon status tunggal redux ketika saya perlu mengelola data beberapa sesi. Saya memiliki jumlah cabang yang berubah-ubah dengan bentuk yang identik dan masing-masing memiliki beberapa pengenal unik (tergantung dari mana datanya berasal, Anda akan menggunakan kunci yang berbeda). Kesederhanaan fungsi peredam dan fungsi pemilihan ulang dengan cepat menghilang ketika dihadapkan dengan persyaratan tersebut - harus menulis pengambil / penyetel khusus untuk menargetkan cabang tertentu terasa terlalu kompleks dan datar dalam lingkungan yang sederhana dan dapat disusun. Saya tidak tahu apakah banyak penyimpanan adalah pilihan terbaik untuk mengatasi persyaratan itu, tetapi beberapa perkakas seputar mengelola sesi (atau data berbentuk identik lainnya) ke dalam satu pohon keadaan akan menyenangkan.

Peningkatan kemungkinan tabrakan kunci status antara pereduksi.
Mutasi dan deklarasi data jauh dari kode tempat data digunakan (saat kami menulis kode, kami mencoba menempatkan deklarasi variabel di dekat tempat kami menggunakannya)

Izinkan saya memberi pengantar dengan kasus penggunaan khusus saya: Saya menggunakan Redux dengan dom virtual, di mana semua komponen UI saya murni berfungsi dan tidak ada cara untuk memiliki status lokal untuk berbagai komponen.

Dengan itu, pasti bagian tersulit adalah mengikat dalam keadaan animasi . Contoh berikut adalah dengan mempertimbangkan status animasi, tetapi sebagian besar dapat digeneralisasikan ke status UI .

Beberapa alasan mengapa status animasi canggung untuk Redux:

  • Data animasi sering berubah
  • Tindakan khusus animasi mencemari riwayat tindakan di aplikasi Anda, sehingga sulit untuk melakukan roll-back tindakan dengan cara yang berarti
  • Pohon status Redux mulai mencerminkan pohon komponen jika ada banyak animasi khusus komponen
  • Bahkan status animasi dasar seperti animationStarted atau animationStopped mulai menunjukkan status pasangan ke UI Anda.

Di sisi lain, pasti ada tantangan untuk membangun status animasi sepenuhnya di luar pohon status Redux.

Jika Anda mencoba membuat animasi sendiri dengan memanipulasi DOM, Anda harus berhati-hati terhadap hal-hal seperti ini:

  • virtual-dom diff tidak akan memperhitungkan manipulasi animasi Anda, seperti gaya kustom yang Anda setel pada node — jika Anda menyetel beberapa gaya pada node DOM, Anda harus menghapusnya sendiri jika Anda ingin gaya tersebut menghilang
  • Jika Anda menjalankan animasi pada dokumen itu sendiri, Anda harus sangat berhati-hati dengan pembaruan dom virtual — Anda dapat memulai animasi pada satu simpul DOM, hanya untuk menemukan bahwa konten simpul DOM tersebut diubah di tengah-tengah animasi
  • Jika Anda melakukan animasi pada dokumen itu sendiri, Anda harus berhati-hati dengan gaya dan atribut penimpaan dom virtual yang Anda atur pada node Anda, dan Anda harus berhati-hati terhadap gaya penimpaan dan atribut yang ditetapkan oleh virtual-dom

Dan jika Anda mencoba membiarkan dom virtual menangani semua manipulasi DOM (yang seharusnya Anda lakukan!) Tetapi tanpa mempertahankan status animasi di Redux, Anda akan mendapatkan masalah sulit seperti ini:

  • Bagaimana Anda mengekspos status animasi ke komponen Anda? Status lokal di komponen Anda? Beberapa negara global lainnya?
  • Biasanya logika negara Anda ada di reduksi Redux, tetapi sekarang Anda harus menambahkan banyak logika rendering langsung ke komponen Anda untuk bagaimana mereka akan dianimasikan sebagai respons terhadap status Anda. Ini bisa sangat menantang dan bertele-tele.

Saat ini ada proyek luar biasa seperti react-motion yang membuat kemajuan besar dalam memecahkan masalah ini _untuk React_, tetapi Redux tidak eksklusif untuk React. Saya rasa juga tidak seharusnya demikian — banyak orang membawa lapisan tampilan mereka sendiri dan mencoba untuk berintegrasi dengan Redux.

Bagi siapa pun yang penasaran, solusi terbaik yang saya temukan untuk Redux + virtual-dom adalah dengan menyimpan dua atom negara: Redux menyimpan status aplikasi inti, memegang logika inti untuk memanipulasi keadaan itu sebagai respons terhadap tindakan, dll. Keadaan lainnya adalah objek yang bisa berubah yang menyimpan status animasi (saya menggunakan mobservable). Triknya kemudian adalah berlangganan kedua perubahan status Redux _ dan_ perubahan status animasi, dan merender UI sebagai fungsi dari keduanya:

/* Patch h for jsx/vdom to convert <App /> to App() */
import h from './h'
import { diff, patch, create } from 'virtual-dom'
import { createStore } from 'redux'
import { observable, autorun } from 'mobservable'
import TWEEN from 'tween.js'
import rootReducer from './reducers'
import { addCard } from './actions'
import App from './containers/App'

// Redux state
const store = createStore()

// Create vdom tree
let tree = render(store.getState())
let rootNode = create(tree)
document.body.appendChild(rootNode)

// Animation observable
let animationState = observable({
  opacity: 0
})

// Update document when Redux state 
store.subscribe(function () {
  // ... anything you need to do in response to Redux state changes
  update()
})

// Update document when animation state changes
autorun(update)

// Perform document update with current state
function update () {
  const state = store.getState()
  let newTree = render(state, animationState)
  let patches = diff(tree, newTree)
  rootNode = patch(rootNode, patches)
  tree = newTree
}

// UI is a function of current state (and animation!)
function render (state, animation = {}) {
  return (
    <App {...state} animation={animationState} />
  )
}

// Do some animations
function animationLoop (time) {
  window.requestAnimationFrame(animationLoop)
  TWEEN.update(time)
}
animationLoop()

new TWEEN.Tween(animationState)
      .to({ opacity: 100 }, 300)
      .start()

// Or when you dispatch an action, also kick off some animation changes...
store.dispatch(addCard())
/* etc... */

Terima kasih atas tanggapan yang luar biasa! Biarkan mereka datang.

Satu hal yang perlu diperhatikan adalah kami tidak bermaksud menggunakan Redux untuk status _all_. Apa pun yang tampak penting bagi aplikasi. Saya berpendapat input dan status animasi harus ditangani oleh React (atau abstraksi status ephemeral lainnya). Redux bekerja lebih baik untuk hal-hal seperti data yang diambil dan model yang dimodifikasi secara lokal.

@tokopedia

Saya merasa sulit untuk menggunakan pohon status tunggal redux ketika saya perlu mengelola data beberapa sesi. Saya memiliki jumlah cabang yang berubah-ubah dengan bentuk yang identik dan masing-masing memiliki beberapa pengenal unik (tergantung dari mana datanya berasal, Anda akan menggunakan kunci yang berbeda). Kesederhanaan fungsi peredam dan fungsi pemilihan ulang dengan cepat menghilang ketika dihadapkan dengan persyaratan tersebut - harus menulis pengambil / penyetel khusus untuk menargetkan cabang tertentu terasa terlalu kompleks dan datar dalam lingkungan yang sederhana dan dapat disusun.

Apakah Anda keberatan membuat masalah yang menjelaskan kasus penggunaan Anda secara lebih detail? Mungkin ada cara sederhana untuk mengatur bentuk negara bagian secara berbeda yang Anda lewatkan. Secara umum, banyak cabang dengan bentuk keadaan yang sama tetapi dikelola oleh reduksi yang berbeda merupakan anti-pola.

@tokopedia

Peningkatan kemungkinan tabrakan kunci status antara pereduksi.

Maukah Anda menjelaskan bagaimana ini terjadi secara lebih rinci? Biasanya kami menyarankan Anda untuk hanya menjalankan satu peredam pada bagian mana pun. Bagaimana tabrakan bisa terjadi? Apakah Anda melakukan banyak lintasan di negara bagian? Jika ya, mengapa?

@gaearon @istarkov : mungkin yang dimaksud adalah bahwa berbagai plugin dan pustaka terkait mungkin berdesak-desakan untuk namespace tingkat atas yang sama? Library A menginginkan kunci teratas bernama "myState", begitu pula Library B, dll.

Ya, ini adalah poin yang bagus meskipun bukan itu yang dimaksud @istarkov . (Saya tidak tahu.) Secara umum perpustakaan harus menawarkan cara untuk memasang peredam di mana saja di pohon tetapi saya tahu bahwa beberapa perpustakaan tidak mengizinkannya.

@gaul

Apakah Anda keberatan membuat masalah yang menjelaskan kasus penggunaan Anda secara lebih detail? Mungkin ada cara sederhana untuk mengatur bentuk negara bagian secara berbeda yang Anda lewatkan. Secara umum, banyak cabang dengan bentuk keadaan yang sama tetapi dikelola oleh reduksi yang berbeda merupakan anti-pola.

Saya akan dengan senang hati! Saya akan melakukannya ketika saya punya waktu.

Saya pikir itu pasti dianggap sebagai antipattern, meskipun saya memiliki peredam tunggal, bersama, untuk mengelola cabang-cabang itu. Meskipun demikian, saya merasa paradigma yang disediakan redux tidak jauh dari kasus penggunaan yang sempurna untuk serialisasi / deserialisasi cabang identik sebagai keadaan tidak berubah. Saya tidak mengerti mengapa akan bertentangan dengan etos redux untuk membangun sesuatu seperti pemilihan ulang dengan beberapa logika yang diasumsikan untuk menargetkan cabang tertentu dengan beberapa kunci.

Saya akan senang membicarakannya secara off-thread, saya bisa saja salah.

@taggartbg : berbicara sepenuhnya tanpa mengetahui seperti apa kode Anda di sini. Apakah Anda berbicara tentang mencoba menghadapi keadaan yang terlihat seperti ini?

{ groupedData : { first : {a : 1, b : 2}, second : {a : 3, b : 4}, third : {a : 5, b, 6} }

Sepertinya Anda bisa mengatasinya di sisi peredam dengan memiliki fungsi peredam tunggal yang mengambil kunci ID per grup sebagai bagian dari setiap tindakan. Bahkan, pernahkah Anda melihat sesuatu seperti https://github.com/erikras/multireducer , https://github.com/lapanoid/redux-delegator , https://github.com/reducks/redux-multiplex , atau https://github.com/dexbol/redux-register?

Selain itu, di sisi pemilihan ulang, fakta bahwa React-Redux sekarang mendukung pemilih per komponen mungkin membantu, karena itu meningkatkan skenario di mana Anda melakukan seleksi berdasarkan props komponen.

@gaul

Satu hal yang perlu diperhatikan adalah kami tidak bermaksud menggunakan Redux untuk semua status. Apa pun yang tampak penting bagi aplikasi. Saya berpendapat input dan status animasi harus ditangani oleh React (atau abstraksi status ephemeral lainnya). Redux bekerja lebih baik untuk hal-hal seperti data yang diambil dan model yang dimodifikasi secara lokal.

Pengembang React yang membaca dokumen dan tutorial sudah memiliki abstraksi status singkat ini, jadi mungkin ini sudah ada dalam pikiran saat mempertimbangkan di mana Redux masuk akal untuk sebuah proyek.

Namun, dari perspektif pengembang dengan sedikit atau tanpa pengalaman dengan React yang ingin menggunakan pendekatan fungsional untuk UI, mungkin tidak jelas status mana yang termasuk dalam Redux. Saya telah melakukan beberapa proyek sekarang di mana pada awalnya Redux dan virtual-dom sudah cukup, tetapi seiring bertambahnya kompleksitas aplikasi, "abstraksi keadaan sementara" lainnya menjadi diperlukan. Ini tidak selalu terlihat saat pertama kali Anda menambahkan peredam animasi dengan beberapa bendera animasi dasar, tetapi kemudian menjadi cukup merepotkan.

Mungkin bagus bagi dokumen untuk menyebutkan status mana yang tepat untuk Redux dan status mana yang lebih baik diselesaikan dengan perkakas lain. Ini mungkin berlebihan untuk pengembang React, tetapi bisa sangat bermanfaat bagi pengembang lain untuk memikirkannya ketika melihat Redux dan merencanakan arsitektur aplikasi mereka.

EDIT: judul terbitannya adalah "Apa kerugian menyimpan semua negara Anda dalam satu atom yang tidak dapat diubah?" Ini "semua keadaan Anda dalam satu atom yang tidak berubah" adalah jenis kata yang tepat yang akhirnya mendapatkan banyak jenis keadaan yang salah di pohon Redux. Dokumentasi dapat memberikan beberapa contoh eksplisit untuk membantu pengembang menghindari jebakan semacam ini.

@gaearon Kami melakukan percakapan yang menarik di Cycle.js tentang perbedaan arsitektural antara status atom tunggal vs pipping. DI SINI .

Saya tahu ini tidak 100% terkait dengan Redux tetapi ingin memberikan perspektif yang berbeda dari implementasi yang menggunakan aliran yang dapat diamati sebagai aliran data di sekitar aplikasi (untuk Cycle aplikasi menjadi satu set fungsi murni).

Karena semua yang ada di Cycle adalah Observable, saya mengalami kesulitan untuk berpindah dari satu perubahan rute ke perubahan lain. Ini karena status Observable yang tidak memiliki pelanggan setelah rute diubah dan berpikir mengapa tidak menerapkan status atom tunggal, jadi setiap kali status berubah di aplikasi saya, itu akan melaporkan kembali ke toko tingkat atas, melewati perpipaan apa pun ( tampilan mengerikan gambar di sini ).

Dengan Siklus karena efek samping terjadi pada Driver, Anda biasanya harus membuat putaran itu dari driver tingkat atas ke komponen dan kembali, jadi saya ingin melewatkannya dan langsung kembali ke atas dan ke komponen mendengarkan. Mengambil Redux sebagai sumber inspirasi.

Ini bukan kasus yang benar atau salah, tetapi sekarang saya melakukan pemipaan dan kami telah menemukan driver status, memiliki kemampuan untuk menyalurkan status saya ke berbagai komponen yang saya butuhkan sangat fleksibel untuk refactoring, prototyping, dan memiliki pemahaman yang kuat setiap sumber negara, setiap konsumen, dan bagaimana mereka bisa saling berhubungan.

Juga pendatang baru di aplikasi (jika mereka memahami Siklus tentu saja), dapat dengan mudah menghubungkan titik-titik dan dengan sangat cepat menggambar representasi visual di sana tentang bagaimana status ditangani dan disalurkan dan semua ini dari kode.

Maaf sebelumnya jika ini benar-benar di luar konteks, ingin menunjukkan bagaimana paradigma yang berbeda memiliki percakapan yang serupa: smiley:

@timorr

Setiap widget perlu mempertahankan statusnya sendiri tanpa tumpang tindih di antara keduanya. Tim produk kemungkinan besar ditugaskan untuk setiap widget, jadi mereka mungkin tidak mengetahui pengaruh kode orang lain terhadap lingkungan.

Saya pikir lebih baik jika widget memiliki statusnya sendiri (mungkin bahkan itu sendiri toko (redux?)) Sehingga dapat bekerja secara mandiri di aplikasi (mashup-) apa pun dan hanya menerima beberapa properti saja. Pikirkan tentang widget cuaca. Itu dapat mengambil dan menampilkan data dengan sendirinya dan hanya menerima properti seperti kota, tinggi dan lebar. Contoh lainnya adalah widget Twitter.

Diskusi yang bagus!

Terutama, saya merasa tidak nyaman untuk menggabungkan beberapa aplikasi / komponen / plugin.

Saya tidak bisa begitu saja mengambil modul yang saya buat dan melemparkannya ke modul / aplikasi lain, karena saya harus mengimpor pengurangnya secara terpisah ke dalam penyimpanan aplikasi, dan saya harus meletakkannya di bawah kunci tertentu yang saya modul tahu tentang. Ini juga membatasi saya dari menduplikasi modul jika saya menggunakan @connect , karena terhubung ke seluruh negara bagian.

Sebagai contoh:

Saya sedang membuat messenger yang terlihat seperti iMessage. Ini memiliki status reduks currentConversationId dll. Komponen Messenger memiliki @connect(state => ({ currentConversationId: state.messenger.currentConversationId })) .

Saya ingin menyertakan Messenger dalam aplikasi baru. Saya harus import { rootReducer as messengerRootReducer } from 'my-messenger' dan menambahkannya ke combineReducers({ messenger: messengerRootReducer }) agar berfungsi.

Sekarang, jika saya ingin memiliki dua instance <Messenger> di aplikasi yang memiliki data berbeda, saya tidak bisa, karena saya terikat dengan state.messenger di komponen Messenger. Membuatbekerja terhadap bagian tertentu dari toko akan membuat saya menggunakan @connect disesuaikan.

Juga, katakanlah aplikasi yang memuat memiliki nama tindakan tertentu yang ada pada modul my-messenger , akan ada tabrakan. Inilah sebabnya mengapa kebanyakan plugin redux memiliki awalan seperti @@router/UPDATE_LOCATION .

Beberapa ide acak / gila:

1

@connect dapat terhubung ke bagian tertentu dari toko, jadi saya dapat menyertakan dalam aplikasi saya beberapa <Messenger> s yang terhubung ke bagian data mereka sendiri, seperti state.messenger[0] / state.messenger[1] . Ini harus transparan ke <Messenger> yang masih terus terhubung ke state.messenger , namun, aplikasi yang memuatnya dapat memberikan potongan dengan sesuatu seperti:

@connect(state => ({ messengers: state.messengers }))
class App extends Component {
  render() {
    return (
      <div>
        {this.props.messengers.map(messenger =>
          <ProvideSlice slice={{messenger: messenger}}><Messenger /></ProvideSlice>
        }
      </div>
    )
  }
}

Ada masalah saat menggunakan entitas yang dinormalisasi global, state.entities juga harus ada, jadi bersama dengan status irisan, seluruh status harus ada. ProvideSlice dapat mengatur beberapa konteks yang dapat dibaca Messenger @connect .

Masalah lainnya adalah bagaimana mengikat tindakan yang dipecat oleh komponen di <Messenger> hanya mempengaruhi potongan itu. Mungkin memiliki @connect bawah ProvideSlice menjalankan mapDispatchToProps tindakan hanya pada bagian negara bagian itu.

2

Gabungkan definisi store dan reducer , sehingga setiap peredam juga bisa berdiri sendiri. Menyimpan suara seperti pengontrol sementara peredam adalah tampilan. Jika kita mengambil pendekatan react, "everything is a component" (tidak seperti pengontrol / direktif angular 1.x), ini mungkin memungkinkan komponen dan status / tindakannya benar-benar berdiri sendiri. Untuk hal-hal seperti entitas yang dinormalisasi (yaitu 'keadaan global') sesuatu seperti konteks React dapat digunakan, dan dapat diakses melalui semua tindakan (misalnya getState dalam thunk ) / komponen yang terhubung.

@elado Ide paling cerdas yang pernah saya lihat untuk saat ini adalah https://medium.com/@timbur/react -automatic-redux-provider-and-replicators-c4e35a39f1

Terimakasih @ompylasar. Saya sedang dalam perjalanan dengan atm tetapi ketika saya mendapat kesempatan, saya berencana untuk menulis artikel lain yang menjelaskan penyedia secara lebih ringkas untuk mereka yang sudah akrab dengan React dan Redux. Siapa pun yang sudah terbiasa akan menganggapnya gila sederhana / mudah. :)

@gaearon masih ingin mendengar pendapat Anda tentang ini.

Kesal hewan peliharaan terbesar saya adalah lebih sulit untuk membuat, menggunakan kembali, bersarang, dan umumnya bergerak di sekitar komponen kontainer karena ada dua hierarki independen pada saat yang sama (tampilan dan reduksi). Juga tidak sepenuhnya jelas bagaimana menulis komponen yang dapat digunakan kembali yang menggunakan Redux sebagai detail implementasi atau ingin menyediakan antarmuka yang ramah Redux. (Ada pendekatan yang berbeda.) Saya juga tidak terkesan tentang setiap tindakan yang harus dilakukan "sepenuhnya" ke atas alih-alih mengalami arus pendek di suatu tempat. Dengan kata lain, saya ingin melihat sesuatu seperti model status lokal React tetapi didukung oleh reduksi, dan saya ingin membuatnya sangat praktis dan disesuaikan dengan kasus penggunaan nyata daripada abstraksi yang indah.

@ Gaearon ada ide tentang bagaimana mulai menerapkan sistem seperti itu?

@gaul

Dengan kata lain, saya ingin melihat sesuatu seperti model status lokal React tetapi didukung oleh reduksi

Saya pikir bagian yang sulit adalah bahwa status lokal React terkait dengan siklus hidup sebuah komponen, jadi jika Anda mencoba untuk membuat model status lokal di Redux, Anda memiliki akun untuk "pemasangan" dan "pelepasan." Elm tidak memiliki masalah ini karena 1) komponen tidak memiliki siklus hidup, dan 2) "pemasangan" tampilan diturunkan dari model, sedangkan di React, status lokal hanya ada _setelah_ tampilan telah dipasang. (edit: lebih akurat untuk mengatakannya tepat sebelum dipasang, tetapi setelah keputusan untuk memasang sudah dibuat)

Namun seperti yang Anda singgung, Arsitektur Elm - yang "terus berkembang" - memiliki kekurangannya sendiri dan tidak cocok dengan siklus pembaruan dan rekonsiliasi React (misalnya, memerlukan penggunaan optimasi shouldComponentUpdate() ... yang rusak jika Anda secara naif "meneruskan" metode pengiriman di dalam render() .)

Pada titik tertentu, saya merasa seperti hanya menggunakan reduksi + setState dan menyebutnya sehari: D Kecuali / sampai React menemukan cerita untuk mengeksternalisasi pohon status ... meskipun mungkin itulah yang sebenarnya kita diskusikan di sini

Saya kira inilah yang coba dipecahkan oleh @threepointone dengan https://github.com/threepointone/redux-react-local

@acdlite model konseptual Elm bekerja dengan baik untuk keadaan lokal tetapi tampaknya sangat sulit untuk digunakan dalam aplikasi dunia nyata di mana kita harus menggunakan perpustakaan, memberikan fokus pada pemasangan, menangani efek paralaks atau apa pun ... Lihat https: // github.com/evancz/elm-architecture-tutorial/issues/49

@ Klorber Ya saya setuju. Bukankah pada dasarnya itu yang saya katakan? : D

Saya kira kekhawatiran Anda sedikit berbeda. _If_ (besar "jika") Anda menggunakan Arsitektur Elm di React, saya rasa Anda tidak akan mengalami masalah yang Anda sebutkan karena kami masih memiliki akses ke siklus hidup, setState sebagai jalan keluar, dll.

Ya, kami berada di halaman yang sama @acdlite
Arsitektur Elm dengan React akan menyelesaikan masalah ini.
Bahkan Elm mungkin di masa depan karena bisa mengizinkan penggunaan vdom hook.

Namun arsitektur Elm membutuhkan cukup banyak boilerplate. Saya pikir itu tidak benar-benar berkelanjutan kecuali Anda menggunakan Flow atau Ketik untuk tindakan membungkus / membuka bungkus, dan akan lebih baik memiliki cara yang lebih sederhana untuk menangani keadaan lokal ini, seperti solusi @threepointone

Saya memiliki kekhawatiran lain dengan arsitektur Elm adalah bahwa tindakan bersarang berfungsi dengan baik untuk status komponen lokal, tetapi saya pikir itu bukan ide yang baik begitu Anda memerlukan komunikasi antara komponen yang dipisahkan. Jika widget1 harus membuka bungkusnya dan melakukan introspeksi secara mendalam untuk menemukan beberapa peristiwa yang dipicu oleh widget2, ada masalah penggandengan. Saya telah mengungkapkan beberapa pemikiran di sini dan berpikir menggunakan Elm dengan 2 "kotak surat" bisa melakukan pekerjaan itu. Ini juga yang dapat membantu redux-saga dalam arsitektur non-elm dengan acara datar.

Saya mulai memiliki ide bagus tentang cara merancang aplikasi redux yang dapat diskalakan dan akan mencoba menulis sesuatu tentangnya ketika saya kurang sibuk

@gaearon Apakah Anda berbicara tentang react-redux-provide dalam posting terakhir Anda di sini? Saya bertanya karena jika ya, berdasarkan tanggapan Anda, jelas Anda belum cukup memeriksanya.

Juga, terkait penyebutan @acdlite tentang pohon status , inilah tepatnya masalah yang dirancang untuk diselesaikan oleh penyedia.

API yang disediakan oleh provide decorator tentu saja merupakan abstraksi dan ya, saat ini bergantung pada redux , tetapi menganggapnya sebagai bergantung pada redux adalah cara yang salah untuk pikirkanlah, karena ini sebenarnya hanya semacam "perekat" antara komponen dan pohon status, karena React context belum sepenuhnya dikembangkan. Anggap saja sebagai metode yang ideal untuk memanipulasi dan mewakili pohon negara melalui actions dan reducers (yaitu, status toko) sebagai props , di mana Anda bisa pada dasarnya menyatakan actions dan reducers sebagai propTypes (dan / atau contextTypes di masa mendatang) mirip dengan cara Anda import apa pun dalam aplikasi Anda. Ketika Anda melakukan ini, segala sesuatu menjadi sangat mudah untuk dipikirkan. context milik React berpotensi berevolusi untuk menyertakan fitur-fitur dasar ini, dan dalam hal ini, akan membutuhkan waktu 2 detik untuk menghapus dan menghapus @provide dan import provide from 'react-redux-provide' sehingga Anda kemudian dibiarkan dengan komponen sederhana yang tidak lagi bergantung padanya. Dan jika itu tidak pernah terjadi, bukan masalah besar karena semuanya akan terus berjalan dengan sempurna dan dapat diprediksi.

Saya pikir Anda terlalu menyederhanakan masalah. Anda masih perlu menyelesaikan pemasangan dan pelepasan.

@acdlite Punya contoh?

Jika salah satu hal yang Anda maksud adalah (misalnya) mengambil props dari beberapa database berdasarkan id atau apa pun, ini (di antara hampir semua aplikasi praktis lainnya yang dapat Anda pikirkan) dapat dengan mudah dicapai dengan penyedia. Setelah saya menyelesaikan beberapa hal lain yang sedang saya kerjakan, dengan senang hati saya akan menunjukkan kepada Anda betapa mudahnya melakukannya. :)

Mungkin menarik: implementasi status reaktif dibandingkan .
Elm, Redux, CycleJS ... (sedang dalam proses)

Kebutuhan lain yang mungkin untuk beberapa penyimpanan adalah ketika beberapa _time lines_, _time travel_, menyimpan lokasi dan frekuensi penyimpanan dimungkinkan dan diperlukan. Misalnya, user data dan user actions yang khusus untuk satu pengguna dan common data dan group actions khusus untuk sekelompok pengguna (mis. Proyek multi-pengguna bersama atau dokumen). Hal ini memudahkan untuk memisahkan apa yang dapat diurungkan (perubahan pada data pribadi) dari apa yang diperbaiki (pengeditan sudah ditambah oleh pengguna lain) dan juga memfasilitasi siklus penyimpanan dan / atau sinkronisasi yang berbeda.

Kami sedang dalam tahap desain / pengembangan awal dari aplikasi 1.x sudut dengan pola pikir pengembangan 2.0 sudut dan berpikir untuk menggunakan redux. Di masa lalu, Kami telah menggunakan fluks dengan banyak toko yang menanggapi beberapa kiriman umum dan beberapa kiriman khusus.

Redux tampak hebat bagi saya, tetapi saya tidak dapat menjelaskan konsep penyimpanan tunggal untuk keseluruhan aplikasi. Seperti yang juga ditunjukkan orang lain di atas, kami memiliki sejumlah widget besar yang seharusnya dihosting di aplikasi konsumen yang berbeda dan membutuhkan penyimpanan data khusus untuk masing-masing widget tersebut.

Meskipun pereduksi dapat dipisahkan dan dapat hidup dengan fitur / widget yang menggunakannya, kita harus menggabungkan semuanya ketika saatnya membuat toko. Kami ingin melihat widget kami ada tanpa referensi langsung / tidak langsung ke reduksi yang tidak dipedulikannya.

Kami sangat menantikan beberapa panduan dalam bentuk dokumentasi atau komentar untuk menguraikan praktik terbaik dalam situasi seperti itu sebelum mulai menggunakan redux di aplikasi kami. Bantuan apa pun akan sangat dihargai. Terima kasih.

@VivekPMenon : apa kekhawatiran khusus Anda? Ukuran pohon negara bagian? Mampu melakukan tindakan namespace / menjaga peredam tetap terisolasi? Kemampuan untuk menambah atau menghapus reduksi secara dinamis?

Untuk apa nilainya, saya baru saja menyelesaikan daftar tautan yang mengkatalogkan ekosistem addon Redux. Ada sejumlah pustaka yang mencoba menangani beberapa konsep isolasi / duplikasi / pelingkupan tersebut. Anda mungkin ingin melihat halaman reducer dan lokal / komponen untuk melihat apakah salah satu library tersebut dapat membantu kasus penggunaan Anda.

@tokopedia Terima kasih banyak atas jawabannya. Kebingungan saya sebagian besar berada di sekitar poin ke-2 (Isolasi). Asumsikan salah satu tim kami membuat widget A yang berbasis fluks dan perlu menggunakan store untuk mengelola statusnya. Asumsikan mereka akan membuat paket jspm / npm if dan mendistribusikannya. Sama halnya dengan tim lain yang membuat widget B. Ini adalah widget / paket independen dan tidak perlu memiliki ketergantungan langsung / tidak langsung satu sama lain.

Dalam konteks ini, di dunia fluks biasa. Widget A dan B memiliki penyimpanannya sendiri dalam paket mereka (Mereka mungkin mendengarkan beberapa tindakan umum, tetapi menganggap mereka memiliki lebih banyak tindakan yang tidak umum). Dan kedua widget tersebut akan bergantung pada dispatcher global. Dalam pola redux, di mana toko itu akan dibuat (secara fisik). Komponen widget A dan B UI perlu menggunakan instance store untuk mendengarkan perubahan dan mendapatkan status. Dalam fluks biasa, mereka beroperasi pada instans toko mereka sendiri. Saya mencoba memvisualisasikan bagaimana konsep toko tunggal akan bermain dengan situasi ini.

@VivekPMenon ini adalah pertanyaan valid yang coba diselesaikan oleh sebagian dari kita.

Anda bisa mendapatkan beberapa wawasan di sini: https://github.com/slorber/scalable-frontend-with-elm-or-redux

Juga, lihat jawaban saya tentang Redux-saga di sini: http://stackoverflow.com/a/34623840/82609

@slorber Terima kasih banyak atas panduannya. Menantikan ide-ide yang muncul di sini https://github.com/slorber/scalable-frontend-with-elm-or-redux

@taggartbg Apakah Anda akhirnya membuka masalah? Saya tertarik pada hal yang serupa - ketika memiliki react-router dengan sub-pohon independen yang berbeda, saya merasa bermasalah untuk menjaga status rute sebelumnya saat menavigasi ke cabang baru.

@lutfirmansyah

Mari saya mulai dengan mengatakan bahwa redux saga adalah proyek yang luar biasa dengan banyak pemikiran yang dimasukkan ke dalamnya dan ini sama sekali tidak mencoba untuk menguranginya.

Tapi saya tidak akan menggunakannya dalam proyek saya pada kondisi saat ini. Berikut beberapa alasannya

Sagas tidak memiliki kewarganegaraan

Anda tidak dapat membuat serial status generator, mereka masuk akal saat mereka berjalan tetapi mereka terikat sepenuhnya ke status saga. Ini menyebabkan serangkaian batasan:

  • Anda tidak bisa generator perjalanan waktu
  • Anda tidak dapat melacak jalur yang dituju ke status saga saat ini
  • Anda tidak dapat menentukan keadaan awal
  • Anda tidak dapat memisahkan logika bisnis dari status aplikasi [*]
  • Anda tidak dapat menyimpan saga

[*] Ini dapat diartikan sebagai mendefinisikan logika bisnis dalam definisi model aplikasi, membuat M dan C di MVC sama, yang dapat dianggap sebagai antipattern

Tindakan pengiriman bersifat non-deterministik

Salah satu keuntungan besar menggunakan redux adalah menjaga pemahaman sederhana tentang bagaimana negara bereaksi terhadap suatu tindakan. Tetapi redux-saga membuat tindakan rentan terhadap hasil yang tidak terduga karena Anda tidak tahu di bagian mana dari saga Anda memulai.

Status dapat diserialkan

Masalahnya adalah status saga saat ini berdampak pada status aplikasi saat ini, dan orang-orang menekankan tentang menjaga agar status dapat diserialkan, tetapi bagaimana Anda menerjemahkannya ke saga? Jika Anda tidak dapat sepenuhnya membuat status menjadi serial maka Anda tidak _really_ membuat serialisasi. Anda pada dasarnya tidak dapat memulihkan status aplikasi tanpa memulihkan saga juga.


Menyimpan logika di negara bagian itu buruk, dan menurut saya inilah yang dilakukan redux saga.

Tidak masalah untuk mengasumsikan bahwa status aplikasi Anda khusus untuk aplikasi _your_. Artinya, Anda juga boleh berasumsi bahwa status aplikasi dapat diprediksi selama beroperasi di atas aplikasi _your_. Artinya, tidak masalah untuk menyimpan informasi penyimpanan yang menentukan bagaimana aplikasi Anda berperilaku tanpa benar-benar menyimpan logika di sana.

@eloytor

Saya memahami kekhawatiran Anda. Jika Anda melihat masalah redux-saga, Anda akan melihat bahwa hal-hal ini dibahas dan ada solusi yang dapat ditemukan.

Perhatikan juga bahwa redux-saga memilih untuk mengimplementasikan dengan generator, tetapi itu sama sekali bukan persyaratan untuk mengimplementasikan pola saga, dan ada pro dan kontra.

Ada efek pilih yang memungkinkan Anda menggunakan status redux di dalam redux-saga Anda, jadi jika Anda tidak ingin menyembunyikan status di dalam generator, Anda cukup meletakkan status saga Anda di dalam redux-store secara langsung, tetapi ini melibatkan lebih banyak pekerjaan.

Ada alat pengembang saga yang mengizinkan untuk melacak eksekusi saga.

Ada solusi yang mungkin untuk perjalanan waktu tetapi belum ada implementasi konkret

Baik. Topik yang cukup panjang dan sangat menarik. Saya telah membandingkan berbagai pendekatan manajemen negara.

Saya mengingat beberapa hal saat membandingkan:

  1. satu sumber kebenaran
  2. betapa mudah / sulitnya merender di sisi server dan memasukkan data awal di sisi klien
  3. alat pengembang seperti undo / redo dan penyimpanan riwayat persisten setelah memuat ulang.
  4. animasi, animasi, animasi. Saya selalu bertanya pada diri saya _ "bagaimana animasi bekerja dengan solusi a atau b" _. Ini adalah kunci bagi saya karena produk yang saya kembangkan berpusat pada UX. Saya berbagi banyak kebingungan yang dimiliki @jsonnull .
  5. penggunaan kembali komponen di dalam aplikasi lain
  6. hidrasi data yang direferensikan (_major pain_) untuk menjaga integritas (terkait dengan memberi makan data awal dari sisi server atau sumber data lainnya)
  7. komunitas pengembang lain untuk diskusi seperti ini

Jadi ini adalah poin yang saya waspadai ketika memikirkan tentang pengelolaan negara. Redux adalah pemenangnya dengan mencentang sebagian besar kotak. Saya mengenal Redux cukup baik dan itu adalah hal pertama yang membuat saya bernapas dengan tenang di ranah sisi klien js.

Proyek lain yang paling terkenal yang pernah saya lihat adalah pola SAM (_hard untuk masuk ke pola pikir dan tidak ada alat_) dan Mobx (_ Diketahui karena penyimpanannya yang bisa berubah_).

Keduanya berbagi gagasan tentang sumber kebenaran tunggal dan menurut saya menarik untuk melihat bagaimana mereka menanganinya.

Penelitian saya (terbatas tentu saja) tentang Mobx menghasilkan ini:

  1. Mobx (seperti Redux) menganjurkan sumber kebenaran tunggal tetapi sebagai kelas dengan properti yang dapat diamati. Konsep ini menciptakan perbedaan dengan reduks dan fluks secara keseluruhan:

    1. Mobx juga mengadvokasi sub-toko (_nested / bagian dari single global_). Bagi saya ini terlihat sangat mirip dengan skema sisi klien. Agak menjengkelkan karena Anda mungkin memiliki skema di server juga. Saya melihat kesamaan dengan redux-orm . AFAIK sub-penyimpanan dimaksudkan untuk diteruskan ke komponen sebagai alat peraga (dengan cara ini komponen tidak bergantung pada status pemetaan ke alat peraga atau kunci tertentu dari pohon global). Namun melewatkan satu properti mematahkan gagasan saya tentang "properti" - mereka harus mendeskripsikan apa yang dibutuhkan komponen. Ini sebenarnya membuat saya berpikir jika itu akan menjadi masalah jika React propTypes dapat digunakan untuk menentukan bentuk toko yang dilewati. Juga: memiliki store dan sub-store sebagai kelas memungkinkan untuk mereferensikan data secara langsung tanpa perlu normalisasi, tetapi itu tidak ada gunanya jika Anda ingin memberi makan data awal karena:

    2. Gagasan menyimpan sebagai kelas berarti pengembang tidak memiliki serialisasi di luar kotak, yang berarti itulah tugas Anda jika Anda ingin memberi makan data awal.

  2. Histori dan undo / redo dapat dicapai dengan mengambil snapshot dari status setelah diubah. Tetapi Anda perlu menulis serializer, deserializer sendiri. Contoh diberikan di sini: https://github.com/mobxjs/mobx-reactive2015-demo/blob/master/src/stores/time.js
  3. Hal yang baik tentang menulis serializers adalah Anda dapat mengabaikan beberapa hal. sepertinya tempat yang bagus untuk menyimpan data terkait animasi yang tidak persisten. Jadi jika Anda membuat serial, Anda mengabaikannya dan Anda tidak memiliki langkah-langkah ulangi / urung penuh animasi.
  4. Mobx menganjurkan untuk menyimpan derivasi data di toko (sebagai metode penyimpanan) berlawanan dengan reselect + connect dekorator. Ini sepertinya salah bagi saya.
  5. Karena sifatnya yang dapat diamati, mobx memudahkan untuk menentukan komponen murni yang efisien. Perbandingan properti yang dangkal tidak menjadi masalah karena isinya tetap dapat diamati.

Membandingkan SAM dan Redux, saya suka memikirkan bagaimana logika mengalir:

  1. Redux:

    1. Tentukan toko

    2. Tentukan fungsi yang menangani perubahan penyimpanan (reduksi)

    3. Tentukan pengenal peristiwa (tindakan redux) (jenis tindakan redux) untuk setiap perubahan toko dan jalankan peredam khusus saat cocok

    4. Memetakan penyimpanan ke properti penampung komponen, secara opsional meneruskan penangan interaksi pengguna (klik, ketik, sscroll, dll) sebagai fungsi yang hanya memicu aksi event / dispatches.

    5. Komponen memicu peristiwa (tindakan redux) yang cocok dengan semua reduksi

    6. Render dengan status baru.

  2. SAM:

    1. Tentukan toko.

    2. Tentukan fungsi pengakses / penyetel untuk toko. Penyetel ini menerima data apa pun dan murni berdasarkan data yang dicoba untuk mencari tahu di mana harus meletakkannya di penyimpanan dan apakah ia perlu meminta data dari server atau menyimpannya di sana. Mencari tahu apa yang harus dilakukan dengan data tidak selalu memungkinkan hanya dengan memeriksanya, jadi terkadang pengidentifikasi / flag digunakan (seperti isForgottenPassword ). Penyetel ini juga dimaksudkan untuk memvalidasi data dan menyimpan kesalahan sebagai gantinya. Setelah penyetel selesai -> rerender dengan status baru.

    3. Tentukan fungsi yang menerima bagian data, ubah (alternatif reduksi redux) dan jalankan penyetel yang meneruskan data yang diubah. Fungsi-fungsi tersebut sekarang memiliki gambaran tentang bentuk toko. Mereka hanya mengetahui data yang telah mereka lewati.

    4. Memetakan data penyimpanan ke properti penampung komponen tetapi juga wajib untuk meneruskan penangan penangan interaksi pengguna (klik, ketik, gulir, dll). Perhatikan bahwa ini adalah fungsi sebenarnya (dikenal sebagai reduksi di redux) dan bukan fungsi yang menjalankan panggilan pengiriman.

    5. Catatan: tidak ada pengiriman tindakan, reduksi langsung.

Jadi, semua redux, SAM dan Mobx menyimpan status di satu tempat. Cara mereka melakukannya, membawa kemunduran mereka sendiri. Tidak ada yang bisa mengalahkan redux dan ekosistemnya sejauh ini.

Kelemahan terbesar yang saya lihat juga adalah penanganan status non-serializable.
Dalam kasus saya, saya memiliki API plugin dan oleh karena itu tindakan dan logika yang tidak ada hubungannya dengan Redux tetapi perlu berinteraksi dengan aplikasi saya. Jadi pada dasarnya saya perlu membuat ulang sekelompok kelas berdasarkan keadaan tertentu.

Saya sedang mengerjakan beberapa konsep bagaimana menangani jenis status non serializable ini dengan cara yang lebih baik. Termasuk membuatnya kembali dari keadaan tertentu. Saya sudah berhasil memindahkan semuanya kecuali referensi fungsi / objek kembali ke toko. Yang tersisa adalah objek dengan siklus hidup mereka sendiri dengan API yang ditentukan yang berinteraksi dengan aplikasi saya dan dengan tindakan saya. - Terasa mirip dengan komponen React, hanya saja bukan untuk rendering UI tetapi logika kustom.

Saya tidak tahu apakah kalian sudah membaca artikel dari Erik Meijer ini . Hanya kutipan sederhana:

Bertentangan dengan kepercayaan populer, membuat variabel keadaan tidak dapat diubah sama sekali tidak mendekati menghilangkan efek imperatif implisit yang tidak dapat diterima

Mungkin inilah saatnya untuk meninjau kembali semua omong kosong kekekalan ini. Semua orang akan memberi tahu Anda bahwa itu adalah babi kinerja ketika pohon status tunggal tumbuh dalam ukuran. Pola SAM membuat mutasi menjadi warga kelas utama dari model pemrograman, banyak penyederhanaan terjadi ketika Anda melakukannya dari tidak membutuhkan Sagas lagi, ke semua mesin status tambahan yang diperlukan untuk melacak efek (misalnya mengambil).

Artikel tersebut tidak benar-benar mendukung Anda. Erik Meijer mengunjungi kembali "omong kosong kekekalan ini", dan memeluknya sepenuhnya . Dia berpendapat bahwa menghilangkan mutasi negara adalah langkah dasar pertama , mendasar tetapi tidak cukup. Tujuan utamanya adalah penghapusan total efek samping implisit, yang akan membuat manajemen negara menjadi usang (tidak akan ada negara bagian yang harus dikelola!).

Saya penggemar karya Erik Meijer dan akan dengan bersemangat membaca dan mendengarkan apa pun yang dia katakan, sambil juga mengingat bahwa dia tidak beroperasi di bawah batasan bisnis, teknologi, dan intelektual yang sama dengan saya.

Masalah utama dalam rekayasa perangkat lunak adalah bahwa setiap orang tampaknya percaya bahwa tugas IS-A mutasi. Bahasa pemrograman hanya mendukung tugas, mutasi diserahkan kepada interpretasi programmer.

Menambahkan pembungkus fungsi ke sekumpulan tugas tidak akan secara otomatis menjadi cara terbaik untuk mengubah status. Itu tidak masuk akal.

Ada teori dibalik Mutasi Negara (Aplikasi), namanya TLA +, anehnya ... Erik tidak pernah menyebut TLA + ...

JJ-

Izinkan saya menjelaskannya karena tampaknya ada banyak kebingungan. Makalah Erik menunjukkan dengan fasih bahwa bahasa pemrograman imperatif agak rusak dalam hal status mutasi. Saya yakin semua orang setuju akan hal itu.

Pertanyaannya adalah bagaimana Anda pergi dan memperbaikinya? Tidakkah Anda setuju bahwa ini adalah jenis masalah yang membutuhkan pendekatan " prinsip pertama "?

Ada satu prinsip yang dapat kita sepakati dalam ilmu komputer, Dr. Lamport menyatakannya sebagai: "Banyak dari ilmu komputer adalah tentang mesin negara." dan dia melanjutkan: "Namun ilmuwan komputer begitu terfokus pada bahasa yang digunakan untuk menggambarkan komputasi sehingga mereka sebagian besar tidak menyadari bahwa bahasa-bahasa itu semuanya mendeskripsikan mesin negara."

Memang semua bahasa pemrograman memungkinkan kita untuk menentukan "mesin negara" terlepas dari semantiknya. Sayangnya banyak bahasa pemrograman yang condong ke arah "tindakan" daripada "tindakan negara". Itu untuk alasan yang bagus, ada kelas besar masalah yang jauh lebih efisien dikodekan dengan formalisme berbasis tindakan (di mana keadaan mesin negara sebagian besar dapat diabaikan). Ketika Anda mengabaikannya, Anda pada dasarnya menyatakan bahwa semua tindakan mungkin dilakukan dalam keadaan tertentu, yang kita semua tahu secara umum tidak benar.

Anda bisa tertawa sebanyak yang Anda inginkan tentang contoh haha ​​Erik:
// prints Ha var ha = Ha(); var haha = ha+ha;

tetapi semua yang dia nyatakan adalah bahwa Anda mengambil tindakan yang salah dalam keadaan tertentu. Tidak lebih, tidak kurang.

Apa yang dibawa oleh pemrograman fungsional ke meja? tidak terlalu banyak. Ini mengungkapkan dengan cara yang sangat berbelit-belit hubungan antara mengambil tindakan dan hasil yang mungkin dimilikinya. Ini seperti mencoba melempar panah (bahkan panah monadik pintar) ke labirin raksasa dan berharap Anda akan mencapai target Anda.

TLA + menghadirkan cara yang jauh lebih alami untuk menangani efek, pertama karena TLA + memiliki pengertian yang jelas tentang apa itu langkah dan bagaimana mutasi berkaitan dengan tindakan. Anda bebas mengabaikan TLA +, tetapi sepertinya Anda mengeluh Anda mencoba mengirim roket ke bulan dengan asumsi bumi datar dan sangat sulit untuk mengarahkan pesawat luar angkasa. Saya tahu bahwa kita hidup di dunia di mana orang percaya bahwa mereka dapat membelokkan kenyataan, selama cukup banyak orang yang percaya apa yang mereka katakan ... bahwa itu masih tidak akan membawa Anda kemana-mana.

Jadi sekali lagi, saya akan sangat, sangat, sangat ingin tahu apa pendapat Erik tentang TLA +, saya terhubung dengannya di LinkedIn dan mengajukan pertanyaan. Tidak pernah mendapat jawaban ... Bagaimanapun, Dr. Lamport hanya mendapat penghargaan Turing untuk itu, itu mungkin tidak sebanding dengan waktunya.

Sejujurnya, @jdubray , saat ini Anda sedang berada di ambang batas. Anda telah mengulangi argumen Anda puluhan kali di utas ini, masalah lain, dan di tempat lain. Anda telah menghina Dan dan komunitas Redux, Anda telah melambaikan kredensial Anda, dan terus menggunakan kata-kata "TLA +" dan "Lamport" seolah-olah itu adalah Cawan Suci dan Jawaban untuk Kehidupan, Semesta, dan Segalanya. Anda telah bersikeras bahwa SAM jauh lebih unggul dari Redux, tetapi tanpa banyak menulis aplikasi perbandingan yang bermakna, meskipun banyak undangan untuk menunjukkan bukti. Anda benar-benar tidak akan mengubah pikiran siapa pun yang belum yakin sekarang. Sejujurnya saya menyarankan Anda untuk menghabiskan waktu Anda melakukan sesuatu yang lebih produktif.

Saya akan menutup utas saat ini. Komentar bisa berlanjut, saya rasa, tapi jelas tidak ada yang bisa ditindaklanjuti di sini.

@markerikson Saya ingin diskusi ini tetap berjalan meskipun tidak mengarah ke mana pun, topiknya sedikit menarik bagi saya. Akan lebih baik untuk menghapus komentar beracunnya dan menjaga agar diskusi sumber terbuka tetap berjalan.
Selain @antitoxic (tidak ada intervensinya sehingga tidak ada gunanya mendengarkan lagi

Tidak apa-apa Tandai Anda dapat menghapus komentar saya, mengapa merusak percakapan yang begitu brilian?

@jdubray hanya Anda yang melihatnya sebagai brilian. Saya pikir kita semua merasa Anda mencoba menjual sesuatu kepada kami tanpa lebih banyak argumen daripada "Lamport mendapat penghargaan Turing, jadi dengarkan saya, saya benar!".

Saya tidak mengatakan TLA + atau apa pun yang tidak baik, dan mungkin di masa depan seseorang akan melakukan pekerjaan yang lebih baik daripada Anda menjualnya. Hanya cara Anda menjelaskannya yang tidak membantu kami untuk memahami sama sekali, dan nada rendah hati Anda yang terus menerus tidak mengundang saya untuk menginvestasikan waktu untuk mempelajari TLA +.

Makalah Erik menunjukkan dengan fasih bahwa bahasa pemrograman imperatif agak rusak dalam hal status mutasi. Saya yakin semua orang setuju akan hal itu.

Sebenarnya Anda selalu menggunakan istilah seperti I believe everyone agrees on that di semua posting Anda. Ini bukanlah sesuatu yang baik, membantu atau menyambut orang lain. Kami tidak semua setuju dengan Anda secara default, dan kebanyakan dari kami tidak dan tidak akan membaca makalah Erik. Jika Anda tidak dapat meyakinkan orang dengan cara yang ramah, tanpa meminta mereka membaca banyak kertas sebelumnya, dan membuat mereka merasa bodoh jika tidak atau tidak setuju dengan Anda, itu tidak akan membantu menyebarkan ide-ide Anda.

Anda bebas mengabaikan TLA +, tetapi sepertinya Anda mengeluh Anda mencoba mengirim roket ke bulan dengan asumsi bumi datar dan sangat sulit untuk mengarahkan pesawat luar angkasa.

Ini secara definitif terlihat seperti analogi dan tentunya bukan prinsip pertama . Sungguh, apakah menurut Anda pernyataan ini dianggap sebagai "diskusi yang cemerlang"?

Saya pikir diskusi sebenarnya lebih cemerlang ketika Anda tidak berbicara di dalamnya, karena Anda memonopoli semua perhatian pada TLA + dan sebenarnya mencegah orang yang tidak tertarik dengan TLA + untuk mencoba mengirim roket mereka ke bulan dengan sesuatu yang lebih konkret, daripada rata-rata. orang bisa mengerti, seperti Redux.

Masih tidak mengatakan TLA + tidak layak, hanya Anda membicarakannya dengan cara yang salah, kepada orang yang salah. Mungkin jika Erik tidak menjawabmu, itu karena dia juga tidak bisa memahamimu? Mungkin Anda sangat pintar sehingga hanya Lamport yang bisa mengerti Anda? Mungkin di masa depan Anda akan memenangkan penghargaan Turing? Saya tidak tahu, tapi satu hal yang pasti adalah diskusi saat ini tidak membawa apapun ke meja perundingan.

Mungkin suka @gaearon dan membuat tutorial video TLA + / SAM untuk orang bodoh. Jika Anda dapat menjelaskan ide Anda dengan cara yang sangat sederhana, di bawah 2 jam video, dan pada akhirnya pola Anda klik dan merasa berguna bagi pengembang, Anda menang. Redux melakukan itu untuk banyak orang. Anda hanya "mencoba" untuk menjelaskan secara teoritis mengapa SAM / TLA + lebih baik daripada Redux, dan memberikan implementasi TodoMVC yang tampak mengerikan. Kami adalah peneliti CS di sini, kami membutuhkan material konkret. Dapatkah Anda menunjukkan kepada kami sebuah aplikasi, yang ditulis dalam Redux vs yang ditulis dalam SAM, di mana orang akan merasa bahwa penerapan SAM lebih baik? Itu belum terjadi sejauh ini.

@Niondir Saya menemukan cara untuk menggunakan saga dalam kasus di mana Anda perlu memulihkan status.
Ini lebih seperti pola atau seperangkat aturan untuk diikuti

  • Pisahkan hikayat Anda sehingga masing-masing hikayat tidak lebih dari satu put . Jika Anda memiliki saga dengan lebih dari put di dalamnya, pisahkan dan rangkai dengan efek call . Misalnya
function* mySaga() {
  yield put(action1());
  yield put(action2());
}

// split into

function* mySaga() {
  yield put(action1());
  yield call(myNextSaga);
}

function* myNextSaga() {
  yield put(action2());
}
  • Sagas dengan take efek harus dipecah menjadi logika yang mengikuti take dan titik awal saga. Misalnya
function* mySaga() {
  yield take(ACTION);
  // logic
}

// split it into

function* rootSaga() {
  yield takeLatest(ACTION, mySaga);
}

function* mySaga() {
  // logic
}
  • Untuk setiap saga membuat semacam fitur "checkpoint", yang berarti bahwa di init baca dari negara bagian dan dari sana call saga yang Anda butuhkan
function* rootSaga() {
  // emit all forks and take effects that need to run in the background
  yield call(recoverCheckpoint);
}

function* recoverCheckpoint() {
  const state = yield select();
  if (state.isFetching) {
    // run the saga that left the state like this
  }
}

Penjelasan mengapa ini akan berhasil didasarkan pada serangkaian asumsi yang umumnya benar

  • take efek memerlukan tindakan untuk dikirim ke toko, aman untuk selalu memanggil saga ini di init bahkan jika Anda sedang memulihkan karena mereka tetap diam sampai pengguna berinteraksi dengan halaman dan / atau saga sudah berjalan
  • Tidak mengizinkan lebih dari satu panggilan put per saga memungkinkan terjadinya perubahan atomik dalam status, dengan cara yang sama tindakan hanya dapat mengubah status dalam satu cara saga juga terbatas pada kapasitas itu, yang jenis pembuatannya korelasi antara saga dan pengiriman tindakan.

Memisahkan saga dengan cara ini juga memiliki beberapa _efek_ positif

  • Sagas lebih dapat digunakan kembali
  • Sagas lebih mudah diubah
  • Sagas lebih mudah dipahami

tapi @lorber :

Banyak orang menganggap sampel "game memancing" ini cukup menarik untuk dikodekan karena ini mengilustrasikan secara langsung bagaimana SAM bekerja secara keseluruhan, termasuk representasi status dinamis dan "predikat-aksi-berikutnya". NAP mengurangi kebutuhan akan Sagas, dan tidak perlu melanggar prinsip Redux # 1 yang merupakan pohon status tunggal, tetapi apa yang saya ketahui?

Kadang-kadang ketika saya menggunakan Ableton Live, pikiran muncul di kepala saya "mungkinkah menulis GUI Ableton Live sebagai aplikasi React / Redux?" Saya pikir jawabannya adalah tidak, akan terlalu sulit untuk mendapatkan kinerja yang dapat diterima. Ada alasan mengapa itu ditulis dalam Qt dan alasan mengapa Qt memiliki arsitektur sinyal / slot.

Saya telah menggunakan React / Redux dengan Meteor. Saya menyimpan dokumen mongo dalam status Immutable.js dengan mengirimkan tindakan Redux untuk callback ke Mongo.Collection.observeChanges . Saya baru-baru ini menemukan bahwa ketika berlangganan beberapa ribu dokumen, UI sangat lamban saat memulai karena ribuan tindakan Redux dikirim saat Meteor mengirim hasil langganan awal satu per satu, menyebabkan ribuan operasi Immutable.js dan ribuan perenderan secepatnya mungkin. Saya berasumsi RethinkDB juga berfungsi seperti ini, meskipun saya tidak yakin.

Solusi saya adalah membuat middleware khusus yang akan mengesampingkan tindakan pengumpulan tersebut dan kemudian mengirimkannya dalam batch dengan kecepatan yang dibatasi, sehingga saya dapat menambahkan ~ 800 dokumen dalam satu perubahan status. Ini memecahkan masalah kinerja, tetapi mengubah urutan acara secara inheren berisiko karena dapat menyebabkan keadaan yang tidak konsisten. Misalnya, saya harus memastikan tindakan status langganan dikirim melalui throttler yang sama, sehingga langganan tidak ditandai siap sebelum semua dokumen ditambahkan ke status Redux.

@ jedwards1211 Saya mengalami masalah serupa (banyak pesan kecil yang akan menyusun data awal).

Dipecahkan dengan cara yang sama dengan melakukan pembaruan batch. Alih-alih middleware, saya menggunakan mekanisme antrian khusus (kecil) (mendorong semua pembaruan dalam larik, dan secara berkala jika ada sesuatu untuk memperbarui semuanya pada saat yang sama.

@andreieftimie ya, ini lebih rumit di aplikasi saya karena ada beberapa interaksi UI yang memerlukan pembaruan segera, seperti menyeret dan memperbesar plot. Jadi saya harus memiliki lapisan middleware untuk memutuskan apakah akan segera mengirimkan tindakan atau memasukkannya ke dalam antrian untuk pengiriman batch.

Untuk apa nilainya, saya punya ide untuk membuat "cabang". Ini benar-benar bertentangan dengan prinsip penyimpanan tunggal, tetapi sepertinya kompromi yang baik.

https://github.com/stephenbunch/redux-branch

@ jedwards1211 Saya rasa seiring bertambahnya kompleksitas aplikasi, pada akhirnya ada kebutuhan untuk memecah jenis data tertentu dan jenis pembaruan tertentu sehingga toko tertentu tidak menangani beban penuh.

Misalkan ada beberapa status inti yang ingin Anda sinkronkan dengan backend, ada beberapa status animasi sehingga komponen UI aplikasi Anda ditampilkan dengan benar sesuai dengan tindakan saat ini yang dilakukan, dan mungkin Anda memiliki beberapa data debug yang Anda lacak terpisah.

Dalam contoh yang dibuat-buat ini, tentu saja mungkin untuk membangun semua ini dari satu toko Redux, tetapi tergantung pada bagaimana Anda merancangnya, akan ada beberapa garis kabur antara masalah berbagai cabang pohon negara, dan mungkin kurangnya kejelasan mengenai keadaan mana tindakan tertentu dimaksudkan untuk berinteraksi.

Saya pikir sangat masuk akal untuk menggunakan strategi pengelolaan keadaan yang berbeda sesuai dengan bagaimana keadaan yang Anda inginkan untuk dicakup dan karakteristik kinerja apa yang Anda harapkan darinya. Redux cocok untuk keadaan di mana Anda mungkin ingin mengembalikan atau memutar ulang tindakan, atau membuat serial dan kembali lagi nanti. Untuk status animasi, Anda dapat menggunakan penyimpanan yang bisa berubah atau penyimpanan reaktif jika Anda mau — akan ada lebih sedikit overhead dengan cara itu dan Anda tidak akan mencemari status aplikasi Anda dengan status interaksi sementara ini (tetapi masih perlu).

Sangat cepat, saya ingin menjelaskan dengan arsitektur serat React yang akan datang. Ini tautannya , maaf jika pemahaman saya agak ketinggalan zaman. Secara kasar, arsitektur fiber mengakui bahwa ada berbagai jenis pembaruan yang akan disebarkan melalui pohon komponen React, dan ada ekspektasi yang berbeda mengenai kapan dan bagaimana pembaruan ini akan dilakukan. Anda ingin pembaruan animasi menjadi cepat, responsif, dan andal, dan Anda tidak ingin pembaruan interaksi yang besar menyebabkan jank dalam animasi Anda dan semacamnya.

Jadi arsitektur fiber memecah pembaruan menjadi paket kerja dan menjadwalkannya sesuai dengan prioritas berdasarkan pekerjaan yang sedang dilakukan. Animasi adalah prioritas tinggi — agar tidak terganggu, dan pembaruan mekanis yang lebih lambat memiliki prioritas lebih rendah.

Saya telah melewatkan banyak detail tentang serat React dan mungkin mendapatkan beberapa kesalahan dalam prosesnya, tetapi maksud saya adalah bahwa ini adalah jenis pendekatan terperinci yang menurut saya diperlukan untuk penyimpanan data Anda dengan berbagai jenis data.

Jika saya sedang membangun aplikasi yang kompleks hari ini, saya akan mulai dengan kelas toko tingkat atas seperti Redux yang didukung oleh beberapa toko berbeda. Kurang lebih:

  • Penyimpanan data tingkat atas memiliki antrian untuk tindakan masuk
  • Tindakan dapat berupa tindakan animasi yang harus dikirim dengan cepat, atau interaksi aplikasi yang memiliki prioritas lebih rendah
  • Tindakan animasi dalam antrean dikirim ke backend yang dapat diamati dari loop requestAnimationFrame
  • Tindakan interaksi dikirim ke redux ketika tindakan animasi dari antrian selesai

Kisah ini tampaknya cukup dekat dengan solusi status lengkap berdasarkan Redux. Redux cocok untuk data yang ingin Anda lihat setelah serangkaian tindakan, dan ada banyak kondisi lain di luar sana yang juga perlu ditangani dengan hati-hati.

@jsonnull Saya tidak pernah memiliki kebutuhan untuk menyimpan status animasi di toko - status lokal selalu ideal untuk kasus penggunaan animasi saya. Saya ingin tahu apakah ada beberapa kasus penggunaan yang status animasi lokal sama sekali tidak cocok untuk itu. Kedengarannya mereka memiliki ide bagus untuk arsitektur baru.

@ jedwards1211 Ada beberapa kasus yang dapat saya pikirkan di mana status animasi lokal tidak berfungsi. Saya akan memberi Anda, itu bukan kasus yang akan Anda hadapi dengan setiap aplikasi, tetapi saya pikir mereka cukup sering muncul.

Dalam satu kasus Anda menggunakan perpustakaan selain Redux di mana Anda tidak memiliki negara bagian lokal. (Ok, ya, saya tahu saya sedikit curang di sini.) Jika Anda menggunakan pendekatan hiperskrip yang sangat ramping, tidak ada dom virtual, komponen fungsional murni, alih-alih status lokal Anda harus melewatkan beberapa animasi nyatakan ke node root atau node mana pun yang Anda render ulang.

Dalam kasus ini, memiliki pohon status dengan beberapa set detail animasi akan memungkinkan Anda untuk mengatasi kekurangan status lokal sehingga Anda dapat memicu animasi, menjalankan animasi selama suatu durasi, dan banyak lagi.

Kuncinya di sini adalah ada dua cara untuk melakukan animasi ini — lakukan itu sebagai bagian dari render Anda dan pertahankan metafora "UI sebagai fungsi status" tetap utuh, atau mutasi DOM secara terpisah. Hampir selalu jawaban yang lebih baik adalah dengan hanya merender ulang daripada bermutasi.


Sekarang sebagai contoh di mana Anda memiliki kemampuan untuk menyimpan beberapa status animasi lokal — membuat game browser dengan UI berbasis React di atasnya.

  • Biasanya Anda akan mengemudikan game menggunakan ticks ... waktu game dimulai dari 0 dan bertambah setiap frame. Animasi permainan inti dapat dilakukan di kanvas atau di WebGL di mana tidak ada status lokal, jadi Anda akan mendasarkan waktu mulai dan kemajuan animasi berdasarkan tanda ini.

Contoh: Karakter sprite memiliki animasi yang terdiri dari 10 bingkai, dan Anda ingin memainkan animasinya selama ~ 400 md, jadi Anda akan mengubah sprite yang digambar setiap 2 kutu atau lebih.

Kutu Anda juga bisa menjadi cap waktu jika Anda menginginkan resolusi yang lebih tinggi.

  • Game Anda juga dapat dijeda, dalam hal ini Anda mungkin ingin menghentikan beberapa animasi yang dilakukan di sisi React UI.

Dalam contoh permainan ini, yang tidak ingin Anda lakukan adalah menaikkan tick Anda sebagai bagian dari tindakan tick ... alih-alih Anda ingin menambah tick secara terpisah, mungkin dalam struktur yang dapat diamati. Dan saat Anda mengirimkan tindakan Redux seperti gerakan atau serangan karakter keyboard, Anda akan meneruskan centang saat ini atau waktu saat ini kepada mereka, sehingga Anda dapat merekam centang di mana suatu tindakan terjadi dan komponen UI Anda dapat merekam secara lokal jam berapa animasi dimulai .

Sekarang Anda telah memisahkan status animasi global dari status interaksi, dan jika Anda ingin melakukan "replay" hanya dengan menggunakan status Redux atau dengan memutar ulang tindakan, Anda bisa, dan Anda tidak dibebani dengan menaikkan tick sebagai bagian dari status Anda pohon.

Secara umum, jauh lebih baik untuk mengoordinasikan animasi dengan meneruskan waktu mulai / berhenti melalui Redux dan membiarkan komponen mempertahankan status lainnya secara lokal.

Ini tidak hanya berlaku untuk game. Urutan animasi tambahan apa pun mungkin mengalami ini, seperti jika Anda ingin melakukan serangkaian animasi yang berjalan lama di situs menggunakan React.

@jsonnull cool, itu contoh yang bagus, terima kasih telah membagikannya.

Saya hanya akan mengatakan - di Redux Anda tidak bisa menyimpan objek negara dengan tautan satu sama lain. Misalnya - pengguna dapat memiliki banyak posting dan posting dapat memiliki banyak komentar dan saya ingin menyimpan objek tersebut dengan cara:

var user = {id: 'user1', posts: [], comments: []}
var post = {id: 'post1', user: user, comments: []}
user.posts.push(post);
var comment = {id: 'comment1', post: post, user: user}
post.coments.push(comment)
user.comments.push(comment)
appState.user = user

Redux tidak mengizinkan penggunaan hierarki objek dengan referensi melingkar. Di Mobx (atau Cellx) Anda cukup memiliki referensi satu-ke-banyak dan banyak-ke-banyak dengan objek dan itu menyederhanakan logika bisnis berkali-kali

@bgnorlov Saya tidak berpikir apa pun dalam paket redux melarang referensi melingkar seperti yang Anda bicarakan - mereka hanya membuatnya lebih sulit untuk mengkloning state Anda di peredam Anda. Selain itu, mungkin lebih mudah untuk membuat perubahan status dengan referensi melingkar jika Anda menggunakan Immutable.js untuk mewakili status Anda, meskipun saya tidak yakin.

Anda juga bisa memodelkan hubungan dalam status redux Anda dengan menggunakan kunci asing, meskipun saya mengerti ini tidak senyaman menggunakan referensi objek seperti ORM:

var user = {id: 'user1', postIds: [], commentIds: []}
var post = {id: 'post1', userId: user.id, commentIds: []}
user.postIds.push(post.id);
var comment = {id: 'comment1', postId: post.id, userId: user.id}
post.commentIds.push(comment.id)
user.commentIds.push(comment.id)
appState.userId = user.id
appState.posts = {[post.id]: post}
appState.comments = {[comment.id]: comment}

// then join things like so:
var postsWithComments = _.map(appState.posts, post => ({
  ...post,
  comments: post.commentIds.map(id => appState.comments[id]),
})

@ jedwards1211 untuk
Dengan pendekatan normalisasi ketika beberapa event handler membutuhkan beberapa data yang dibutuhkannya setiap kali mengambil objek dengan idnya dari status global. Misalnya - Saya perlu memfilter tugas saudara di suatu tempat di event handler (tugas dapat memiliki struktur hierarki) Dengan redux saya perlu mengirimkan thunk untuk mendapatkan akses ke status aplikasi

var prevTask = dispatch((_, getState)=>getState().tables.tasks[task.parentId]).children.map(childId=>dispatch((_, getState)=>getState().tables.tasks[childId])).filter(task=>...) [0]

atau dengan penyeleksi

var prevTask = dispatch(getTaskById(task.parentId)).children.map(childId=>dispatch(getTaskById(childId)).filter(task=>...)[0]

dan boilerplate ini mengubah kode menjadi berantakan dibandingkan dengan versi mobx ketika saya bisa menulis

var prevTask = task.parent.children.filter(task=>...)[0]

@ jedwards1211 , @bgnorlov : FWIW, inilah salah satu alasan mengapa saya suka Redux-ORM . Ini memungkinkan Anda untuk menjaga toko Redux Anda tetap normal, tetapi membuat pembaruan dan pencarian relasional menjadi lebih sederhana. Faktanya, contoh terakhir itu pada dasarnya identik dengan Redux-ORM.

Saya baru saja menulis beberapa posting blog yang menjelaskan dasar-dasar Redux-ORM , serta konsep inti dan penggunaan tingkat lanjut .

@markerikson keren, terima kasih atas tipnya!

@gaul

Satu hal yang perlu diperhatikan adalah kami tidak bermaksud menggunakan Redux untuk semua status. Apa pun yang tampak penting bagi aplikasi. Saya berpendapat input dan status animasi harus ditangani oleh React (atau abstraksi status ephemeral lainnya). Redux bekerja lebih baik untuk hal-hal seperti data yang diambil dan model yang dimodifikasi secara lokal.

Saya menemukan komentar ini sangat berguna. Saya tahu saya terlambat ke pesta, tapi mungkin itu bagian dari maksud saya. Lebih dari setahun sejak komentar itu diposting dan ini masih satu-satunya tempat saya melihat ide ini diungkapkan.

Berasal dari latar belakang bersudut dan jelas bukan fluks / reduks, sangat sulit untuk merumuskan ide itu sendiri. Terutama ketika banyak contoh masih membuat tindakan untuk setiap keyup di kotak teks. Saya berharap seseorang meletakkan kutipan itu dalam teks 50px di bagian atas setiap halaman dokumentasi Redux.

@leff Setuju. Saya telah mensintesis ide yang tepat beberapa waktu yang lalu, tetapi itu tidak cukup dikenal. Bahkan jika Anda menggunakan Redux untuk pengelolaan riwayat, sering kali ada banyak keadaan singkat yang tidak perlu membebani pengelolaan keadaan gaya Redux Anda.

Itu tidak akan mengejutkan orang-orang yang pernah memiliki kesempatan untuk mengerjakannya, misalnya aplikasi desktop dewasa yang kaya akan pembatalan / pengulangan. Tetapi bagi lautan pendatang baru yang datang ke ide-ide ini melalui Redux, itu akan menjadi wahyu.

@bgnorlov itu poin bagus bahwa tidak mungkin untuk menyimpan referensi melingkar dengan Immutable.js, saya tidak pernah memikirkannya! Saya pikir itu fitur yang bagus.

Hari-hari ini kita cenderung menyimpan hampir semua hal di Redux, meskipun itu adalah status khusus tampilan sementara yang tidak pernah kita gunakan di luar konteksnya (misalnya status untuk instance redux-form ). Dalam kebanyakan kasus, kami dapat mengeluarkan status seperti itu dari redux tanpa mengalami masalah apa pun. Tetapi keuntungannya adalah jika kita membutuhkan komponen eksternal untuk meresponsnya di masa depan. Misalnya, kami mungkin memiliki beberapa ikon di bilah navigasi yang berubah ketika ada formulir yang salah atau sedang dikirim.

Saya akan mengatakan hal yang paling penting untuk diingat adalah bahwa menempatkan semua status yang dinormalisasi di Redux (yaitu apa pun yang perlu digabungkan untuk membuat tampilan) akan membuatnya paling mudah digunakan. Status yang tidak perlu digabungkan dengan apa pun mungkin dapat hidup di luar Redux tanpa menimbulkan kesulitan bagi Anda, tetapi biasanya juga tidak ada salahnya untuk memasukkannya ke dalam Redux.

FWIW, dokumen menunjukkan bahwa tidak semuanya harus masuk ke Redux, sesuai http://redux.js.org/docs/faq/OrganizingState.html#organizing -state-only-redux-state.

Ada cukup banyak obrolan online baru-baru ini tentang apa Redux "cocok untuk". Beberapa orang melihat manfaat dari memasukkan semuanya secara harfiah ke dalam Redux, yang lain merasa itu terlalu merepotkan dan hanya ingin menyimpan data yang diambil dari server. Jadi, jelas tidak ada aturan baku di sini.

Seperti biasa, jika ada orang yang memiliki ide untuk meningkatkan dokumen, Humas sangat diterima :)

Jika Anda perlu menggunakan kembali reduksi dan dapat mengalokasikan "sub-status" dalam status redux Anda, saya mengembangkan plugin untuk melakukannya dengan mudah (dengan integrasi React)

https://github.com/eloytoro/react-redux-uuid

@eloytoro IMO jika Anda mengalami masalah dengan beberapa peredam pihak ketiga yang memiliki jenis tindakan atau lokasi hardcode di negara bagian tersebut, Anda harus membuka masalah dalam proyek ... tidak lama lagi akan menjadi praktik desain yang tidak dapat diterima karena orang-orang mempelajari peredam / tindakan yang dapat digunakan kembali pola pencipta.

@eloytoro Saya akan menulis sesuatu seperti itu. Terima kasih banyak atas referensinya!

@ jedwards1211 Saya rasa Anda salah

@avesus berharap ini berhasil untuk Anda

@eloytoro ah, itu lebih masuk akal.

Tahun lalu saya membuat game yang cukup kompleks menggunakan Redux. Saya juga telah berpartisipasi dalam proyek lain yang tidak menggunakan Redux, melainkan kerangka kerja minimalis yang dibuat khusus yang memisahkan semuanya menjadi Toko UI dan Toko Server (termasuk input). Tanpa membahas terlalu banyak detail, kesimpulan saya sejauh ini adalah sebagai berikut:

Keadaan tunggal selalu lebih baik, namun jangan berlebihan. Mendapatkan setiap keyDown () melalui penyimpanan dan kembali ke tampilan hanya membingungkan dan tidak perlu. Jadi status transient harus ditangani oleh status komponen lokal (seperti React's).

Saya pikir karena reduks dan reaksi mengobarkan web yang dapat diamati, jumlah animasi yang baik di halaman menurun.

@ mib32 Anda mungkin benar! Semoga orang-orang pada akhirnya akan terbiasa membuat animasi yang bagus di React.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat