Rumah  >  Soal Jawab  >  teks badan

Sekiranya saya meletakkan kod perubahan data dalam fungsi atau hanya dalam tindakan?

Saya sedang menulis aplikasi jadual waktu bas yang menggunakan jenis objek untuk memodelkan "dokumen" jadual waktu.

interface Timetable {
  name: string
  stops: string[]
  services: string[][]
}

Selain jenis, saya mempunyai banyak fungsi, dan jika saya akan menggunakan mutasi, saya biasanya menulisnya sebagai kaedah di kelas. Saya kebanyakannya menggunakan Immer jadi saya tidak perlu menulis banyak sintaks lanjutan. Contohnya,

const addStop = (timetable: Timetable, stopName: string): Timetable => {
  return produce(timetable, (newTimetable) => {
    newTimetable.stops.push(stopName)
  })
}

Untuk menguruskan keadaan saya menggunakan Zustand dan Immer, tetapi saya rasa jika saya menggunakan Redux masalah saya akan menjadi sama. Di kedai saya, saya mempunyai pelbagai objek Jadual Waktu dan operasi yang turut menggunakan Immer untuk menetapkan semula objek Jadual Waktu yang dipilih sekarang:

        updateTt: (tt, index) => {
          set((state) => {
            state.timetables[index] = tt
          })
        },
        updateThisTt: (timetable) => {
          set((s) => {
            if (s.selectedTtIdx === null) {
              throw new Error("no selected timetable")
            }
            s.timetables[s.selectedTtIdx] = timetable
          })
        },

Kemudian saya memanggil fungsi perubahan data dalam komponen React dan memanggil operasi kemas kini:

const onAddStop = (name) => {
  updateThisTt(addStop(timetable, name))
}

Ini berfungsi, tetapi saya tidak pasti sama ada saya melakukannya dengan betul. Saya kini mempunyai dua lapisan panggilan Immer, komponen saya kini mempunyai fungsi pengubahsuaian data yang dipanggil terus dalam pengendali acaranya, dan saya tidak begitu menyukai rupa "kaedah" walaupun ia adalah pepijat kecil secara keseluruhan.

Saya menganggap:

Untuk nilainya, dokumentasi untuk Flux, Zustand atau Immer cenderung menunjukkan pilihan pertama, dan hanya sekali-sekala tiada aplikasi semudah counter = counter + 1. Apakah cara terbaik untuk membina aplikasi menggunakan seni bina Flux?

P粉410239819P粉410239819283 hari yang lalu345

membalas semua(1)saya akan balas

  • P粉576184933

    P粉5761849332024-01-11 16:52:03

    (Saya tidak biasa dengan Zusand dan Immer, tetapi mungkin saya boleh membantu...)

    Selalu ada cara yang berbeza dan saya mencadangkan cara kegemaran saya di sini.

    Bezakan dengan jelas antara tindakan "penjadualan" dan "mutasi" sebenar keadaan. (Mungkintambah tahap lain di antaranya).

    Fungsi "Mutasi" khusus

    Saya syorkan mencipta khusus fungsi "mutasi" dan bukannya yang generik, iaitu:

    • bukannya updateThisTt:() => { ...,
    • Gunakan fungsi seperti addStop: () => { ....

    Buat seberapa banyak fungsi mutasi yang anda perlukan, setiap satu dengan tujuan.

    Bina keadaan baharu dalam fungsi "mutasi"

    Secara konsep, hanya gunakan immer penjana di dalam fungsi mutasi.
    (Maksud saya tentang kedai. Sudah tentu, anda masih boleh menggunakan immer untuk tujuan lain) .

    Berdasarkan contoh rasmi ini :

    import { produce } from 'immer'
    
    const useLushStore = create((set) => ({
      lush: { forest: { contains: { a: 'bear' } } },
      clearForest: () =>
        set(
          produce((state) => {  // <----- create the new state here
            state.lush.forest.contains = null
          })
        ),
    }));
    
    const clearForest = useLushStore((state) => state.clearForest);
    clearForest();

    Di dalam komponen anda kini boleh memanggil fungsi "mutator".

    const onAddStop = (name) => {
      updateThisTt( timetable, name );
    }

    Membina negara baharu

    Jika membina keadaan baharu menjadi rumit, anda masih boleh mengekstrak beberapa fungsi "pembina". Tetapi mula-mula pertimbangkan bahagian seterusnya, "Fail Besar dan Penduaan."

    Sebagai contoh, fungsi addStop anda juga boleh dipanggil dalam mutasi Zustand:

    updateThisTt: ( timetable: Timetable, stopName: string ) => {
        const newTimeTable = addStop( timetable, stopName );
        set( ( s ) => {
            if( s.selectedTtIdx === null ){
                throw new Error( "no selected timetable" )
            }
            s.timetables[ s.selectedTtIdx ] = newTimeTable;
        });
    }

    Fail besar dan pendua

    Penduaan kod pastinya harus dielakkan, tetapi sentiasa ada pertukaran.

    Saya tidak akan mencadangkan pendekatan khusus, tetapi ambil perhatian bahawa kod selalunya lebih banyak dibaca daripada ditulis. Kadang-kadangSaya rasa patut menulis beberapa huruf lagi, seperti sesuatu seperti state.timetables[index] beberapa kali, Jika ia menjadikan tujuan kod lebih jelas. Anda perlu menilai sendiri.

    Apa pun, saya syorkan meletakkan fungsi mutasi anda ke dalam fail berasingan yang tidak melakukan apa-apa lagi, Dengan cara ini, ia mungkin kelihatan lebih mudah untuk difahami daripada yang anda fikirkan.

    Jika anda mempunyai fail yang sangat besar tetapi tertumpu sepenuhnya hanya pada mengubah suai keadaan , Dan strukturnya adalah konsisten, menjadikannya mudah dibaca walaupun anda perlu menatal Beberapa muka surat.

    Sebagai contoh jika ia kelihatan seperti ini:

    // ...
    
    //-- Add a "stop" to the time table 
    addStop: ( timetable: Timetable, stopName: string ) => {
    
       // .. half a page of code ...
       
    },
    
    //-- Do some other specific state change
    doSomethingElse: ( arg1 ) => {
    
       // .. probably one full page of code ...
       
    },
    
    //-- Do something else again ... 
    doSomethingAgain: () => {
    
       // .. another half page of code ...
       
    },
    
    // ...

    Juga ambil perhatian bahawa fungsi variadic ini adalah bebas sepenuhnya (atau adakah mereka? Saya harap Zustand telah menggunakan fungsi tulen di sini, bukan?) .

    Ini bermakna jika ia menjadi rumit, anda juga boleh membahagikan beberapa fungsi mutasi Pisahkan kepada fail berasingan dalam folder Suka /store/mutators/timeTable.js.

    Tetapi anda boleh melakukannya dengan mudah pada bila-bila masa kemudian.

    Bina "payload" ("action caller")

    Anda mungkin merasakan keperluan untuk "tahap" lain Antara pengendali peristiwa dan mutator. Saya biasanya mempunyai lapisan seperti ini, tetapi saya tidak mempunyai nama yang baik untuknya. Mari kita rujuk sementara ini sebagai "Pemanggil Operasi".

    Kadangkala sukar untuk memutuskan apa itu "variogram" dan apa itu "variogram" "Pemanggil tindakan".

    Bagaimanapun anda boleh "membina beberapa data" di dalam "pemanggil tindakan" tetapi anda harus melakukannya Tiada sebarang manipulasi negeri dilakukan di sini , malah dengan immer.

    Mengubah keadaan dan mencipta muatan

    Ini adalah perbezaan yang ketara dan anda mungkin tidak perlu terlalu risau tentangnya (dan mungkin terdapat pengecualian) , tetapi sebagai contoh:

    Anda boleh menggunakan beberapa bahagian keadaan lama di dalam "pemanggil tindakan", contohnya:

    // OK:
    const { language } = oldState;
    const newItem = {  // <-- This is ok: build a new item, use some data for that.
        id: 2,
        language: language,
    };
    addNewItemMutator( newItem ):

    Tetapi anda tidak sepatutnya tidak memetakan (atau mengubah) keadaan lama kepada keadaan baharu, contohnya:

    // NOT OK:
    const { item } = oldState;
    const newItem = {  // <-- This kind of update belongs inside the mutator function.   
        ...item,  
        updatedValue: 'new',
    };
    addNewItemMutator( newItem ):

    Contoh lain

    Tiada cadangan khusus dibuat di sini, hanya contoh:

    Menyalurkan banyak nilai kepada mutator boleh mengelirukan, contohnya:

    const myComponent = ( props ) =>{
        const { name } = props;
        cosnt value = useValue();
        
        // ...
        
        const onAddNewItem: () => {
            const uniqueId = createUUID();
            addNewItemMutator( name, value, uniqueId, Date.now() );
        },

    Dalam pengendali acara, anda ingin memberi tumpuan kepada perkara yang anda mahu lakukan, seperti "tambah item baharu", Tetapi jangan pertimbangkan semua hujah. Selain itu, anda mungkin memerlukan item baharu untuk perkara lain.

    Atau anda boleh menulis:

    const callAddItemAction = function( name, value ){
    
        const newItem = {
            name:        name,
            value:       value,
            uniqueId:    createUUID(),
            dateCreated: Date.now(),
        };
        
        // sendSomeRequest( url, newItem ); // maybe some side effects
        
        addNewItemMutator( newItem );
    }
    
    const myComponent = ( props ) =>{
        const { name } = props;
        cosnt value = useValue();
        
        // ...
        
        const onAddNewItem: () => {
            callAddItemAction( name, value );
        },

    balas
    0
  • Batalbalas