Redux: RFC: Kit Pemula Redux

Dibuat pada 1 Mar 2018  ·  56Komentar  ·  Sumber: reduxjs/redux

Berdasarkan komentar di #2858 dan sebelumnya di #2295, kedengarannya seperti starter kit yang telah dikonfigurasikan dari inti Redux + beberapa middleware umum + peningkat toko + perkakas lain mungkin berguna untuk memulai dengan perpustakaan.

Saya sudah mulai dengan memesan nama paket (saya belum memutuskannya) dan kita bisa mulai mengisi bagian yang kosong di sana. Saya ingin mempertahankan isi paket itu di sini, jadi kami tidak perlu menyiapkan repo lain atau apa pun. Kami mungkin ingin menyelidiki monorepo, tetapi saya tidak berpikir ada kebutuhan mendesak saat ini.

Satu hal yang ingin saya selidiki pada saat yang sama: memisahkan combineReducers ke paketnya sendiri. Ini adalah satu-satunya hal yang menentukan tentang bagaimana menyusun dan mengoperasikan toko. Ini jelas bukan satu-satunya cara, tapi saya khawatir banyak orang tidak melihatnya.

Mengenai apa yang ada dalam paket pemula, daftar singkat dalam pikiran saya termasuk salah satu perpustakaan pengurangan boilerplate (atau sesuatu yang kami buat), middleware populer seperti thunks dan saga, dan alat dev yang membantu. Kami dapat memiliki paket subset untuk pengguna khusus Bereaksi. Sebenarnya, saya memulai jajak pendapat Twitter untuk mencari tahu apakah itu perlu (tolong RT!).

Saya tidak berpikir kita perlu membangun pengalaman seperti Create React App dengan alat CLI dan semua jazz itu. Tetapi sesuatu di luar kotak yang memberikan pengalaman pengembang yang hebat dengan debugging yang lebih baik dan lebih sedikit kode.

discussion ecosystem feedback wanted

Komentar yang paling membantu

Jadi, uh... Aku pergi dan melakukan sesuatu:

Hal-hal yang berbeda dari cuplikan tadi:

  • Saya memasukkan opsi konfigurasi enhancers , hanya karena
  • Saya menambahkan ketergantungan selectorator dan mengekspor createSelector

Pikiran?

Semua 56 komentar

YA YA YA! SAYA PUNYA BANYAK PENDAPAT DAN KEINGINAN UNTUK INI! Tapi saya akan menahan diri dan membiarkan diskusi berjalan lebih dulu.

Satu item daftar keinginan yang saya tidak yakin layak adalah HMR bawaan untuk reduksi yang ditambahkan secara otomatis dalam fungsi createReduxStore() . Sayangnya, pengetahuan saya tentang Webpack dan beberapa eksperimen mengatakan itu tidak terlalu layak, karena Anda harus memiliki jalur hardcoded ke file peredam di panggilan balik Webpack module.hot.accept() . Tidak yakin bagaimana Parcel atau bundler lain menanganinya.

Jadi, permintaan awal untuk umpan balik dari semua orang:

  • Apa persyaratan utama yang ingin kami penuhi dengan paket ini?
  • Paket _existing_ apa yang akan Anda sarankan untuk membantu memenuhi persyaratan tersebut?
  • Bagaimana cara terbaik untuk menggabungkan paket-paket itu agar tetap sederhana bagi pengguna akhir?

Mari sebutkan 3 poin utama, di mana kemungkinan varian akan _terisolasi_ dari satu sama lain.

  1. Poin pertama. Manajer peredam
    1.0 Vanila (APAKAH kasusnya di sini?)
    1.1 Immer.js
    1.2 Coreux
    1.3 100.500 paket lagi

  2. Poin kedua. Middlewares
    2.0 Vanila (apakah demikian?)
    2.1 Saga
    2.2 Epik
    2.3 100.500 paket lagi.

  3. Poin ketiga. Integrasi reaksi
    3.0. Vanila (APAKAH kasusnya di sini?)
    3.1. Subruang
    3.2 Nyatakan kembali
    3.3 100.500 paket lagi.

4, bonus, poin
4.0 Menguji semua hal ini dalam _boilerplate_.

Tidak mungkin untuk memilih "yang terpilih", misalnya saya suka dan menggunakan Sagas dan Epik, tetapi mungkin untuk memberikan beberapa "tanda terima memasak" dan rekomendasi untuk kombinasi .

Misalnya sebagian besar pengguna redux sadar __only__ tentang middlewares. Sebagian kecil juga melakukan sesuatu dengan reduksi (ok banyak _dengar_ tentang immutable.js), hanya beberapa yang meningkatkan integrasi Bereaksi.

Starter Kit hanya bisa membantu membangun pendekatan penuh dan _rich_ dari awal. Atau seseorang membutuhkan lebih dari satu Starter Kit.

Diminta umpan balik tentang titik nyeri setup/boilerplate di Twitter: https://twitter.com/acemarke/status/969040835508604929

Menyalin tanggapan saya di twitter:

Saya secara eksplisit menjauh dari menambahkan boilerplate redux karena IMO itu menambah kerumitan ketika memperkenalkan 'cara Anda' melakukan redux kepada orang lain. Saya ingin lebih banyak konvensi preskriptif yang ditegakkan melalui kode untuk menjadikan redux sebagai keterampilan yang lebih portabel.

Untuk itu, memiliki repo gaya create-redux-app - namun dirancang lebih sebagai perpustakaan daripada kerangka kerja - terutama yang secara eksplisit didukung oleh pengelola Redux dari praktik terbaik dan yang direkomendasikan, saya pikir akan sangat membantu untuk memperkuat dan menambahkan kejelasan pada penggunaan Redux yang tepat.

Kami telah berbicara sedikit tentang ini di Reactiflux, ingin menyalin konsolidasi keinginan untuk dimasukkan dalam utas ini, beberapa di antaranya tumpang tindih dengan poin yang telah Anda daftarkan @timdorr (jadi ini konfirmasi yang antusias).

  1. membungkus createStore dengan default yang lebih baik, yaitu cara yang lebih mudah untuk menambahkan middleware, redux dev tools
  2. built in pembantu yang tidak dapat diubah (immer?)
  3. createReducer bawaan (utilitas "tabel pencarian peredam" standar)
  4. pilih ulang bawaan
  5. pembuat tindakan yang mematuhi FSA
  6. dukungan tindakan async / dukungan efek samping (fluks, saga, apa?)

Mengapa tidak secara resmi mendukung sesuatu yang sudah ada, seperti redux-bundler Henrik Joreteg?

https://github.com/HenrikJoreteg/redux-bundler

Ringkas, berpendirian (dalam cara yang baik), memungkinkan penggunaan kembali fungsionalitas terkait redux di seluruh aplikasi dan masih memberikan solusi yang bagus untuk penanganan async.

Ini adalah proyek yang tampak menarik, dan yang benar-benar ingin saya selidiki lebih lanjut, tetapi juga di luar jangkauan untuk apa yang ingin saya lakukan dengan tugas ini.

Apa yang benar-benar ingin saya capai di sini adalah:

  • Menyiapkan toko Redux dengan beberapa baris kode dan pilihan konfigurasi minimal yang diperlukan (setara Redux dari "zero-config JS" tagline Webpack dan Parcel telah digunakan).
  • Mirip dengan CRA, hal-hal konfigurasi pada dasarnya tersembunyi, dengan default yang bagus di luar kotak
  • Penyertaan paket yang dipilih dengan cermat untuk meningkatkan pengalaman dev dan, ya, "mengurangi boilerplate". Misalnya, Immer akan menjadi pilihan yang bagus karena secara drastis menyederhanakan penulisan logika peredam yang tidak dapat diubah _dan_ membekukan status Anda di dev. (Satu-satunya keraguan saya adalah bahwa tampilan kode yang "bermutasi" akan membingungkan.)

Saya ingin menjaga upaya ini dengan cakupan yang cukup ketat. Saya telah mengobrol dengan @hswolff dan @nickmccurdy di Reactiflux beberapa jam terakhir, dan sementara diskusinya bagus, kami telah menjalankan selusin kasus penggunaan dan ide yang tumpang tindih yang benar-benar dapat memperumit banyak hal.

Saya ingin mendapatkan _sesuatu_ yang berguna, berharga, dan layak disatukan tanpa terlalu banyak kehilangan sepeda, dan kemudian melakukan diskusi lain ke samping (seperti API untuk membuat "bundel" atau "modul" Redux, dll).

Untuk memulai beberapa boilerplating awal API, inilah ide dasar untuk 1-3 daftar saya yang saya posting di atas:

// #1
export function createStore({
    // If an object is given it's passed to combineReducers
    // otherwise it's just used directly.
    reducer: Object<String, Function> | Function,
    // Middleware is built-in and accepts an array of middleware functions.
    middleware: Array<MiddlewareFunction>,
    // Built-in support for devtools.
    // Defaults to NODE_ENV !== production
    devTools: boolean,
    // Same as current createStore.
    preloadedState,
    // Same as current createStore.
    enhancer,
}) {};

// Re-exported for easy usage.
export function combineReducers() {}

// #2
// Re-export immer as the built-in immutability helper.
import immer from 'immer';
export const createNextState = immer;

// #3
// Export an already written version of createReducer .
// Same thing as https://redux.js.org/recipes/structuring-reducers/refactoring-reducers-example#reducing-boilerplate
export function createReducer() {}

Ya, saya menggali itu. Saya kemudian berharap bahwa itu akan selalu menambahkan thunk() di bagian depan daftar middleware, atau mungkin hanya jika Anda tidak menyediakan middlewares sendiri. Kami bahkan mungkin tidak ingin mengizinkan pengguna untuk menentukan penambah di sini. Kami akan menambahkan applyMiddleware() secara otomatis jika ada middleware, dan menggunakan fungsi composeWithDevtools dari redux-devtools-extension if devTools : true . Untuk tujuan hal "pengaturan mudah" ini, saya pikir kita mungkin ingin menghilangkan "peningkat" dari hal-hal yang dapat dikonfigurasi pengguna.

+1 untuk menghilangkan penambah.

Berdasarkan pendapat Anda yang ditambahkan secara otomatis, kami seharusnya dapat memiliki kue kami dan memakannya juga melalui mengekspor fungsi yang akan kami gunakan untuk menambahkan middleware default:

export function createDefaultMiddleware(...additional) {
    return [thunk(), ...additional],
}

// Within a user's application
createStore({
    // By default it's just createDefaultMiddleware()
    // However if you want to add any other middleware you can.
    middleware: createDefaultMiddleware(any, other, middleware)
})

Ya, kira-kira seperti itu yang saya pikirkan. Perhatian utama saya adalah mencari tahu apakah pengguna secara tidak sengaja mencoba menyediakan instance mereka sendiri dari thunk .

Saya memutuskan untuk bermain-main dengan hal-hal sedikit malam ini. Ini potongan pertama. Pikiran?

// configureStore.js
import {createStore, compose, applyMiddleware, combineReducers} from "redux";
import { composeWithDevTools } from 'redux-devtools-extension';
import createNextState from "immer";

import isPlainObject from "./isPlainObject";

import thunk from "redux-thunk";


const IS_DEVELOPMENT = process.env.NODE_ENV !== "production";

export function createDefaultMiddleware(...additional) {
    return [thunk, ...additional];
}

export function configureStore(options = {}) {
    const {
        reducer,
        middleware = createDefaultMiddleware(),
        devTools = IS_DEVELOPMENT,
        preloadedState,
    } = options;

    let rootReducer;

    if(typeof reducer === "function") {
        rootReducer = reducer;
    }
    else if(isPlainObject(reducer)) {
        rootReducer = combineReducers(reducer);
    }
    else {
        throw new Error("Reducer argument must be a function or an object of functions that can be passed to combineReducers");
    }

    const middlewareEnhancer = applyMiddleware(...middleware);

    const storeEnhancers = [middlewareEnhancer];

    let finalCompose = devTools ? composeWithDevTools : compose;

    const composedEnhancer = finalCompose(...storeEnhancers);

    const store = createStore(
        rootReducer,
        preloadedState,
        composedEnhancer
    );

    return store;
}

export function createReducer(initialState, actionsMap) {
    return function(state = initialState, action) {
        const {type, payload} = action;

        return createNextState(state, draft => {
            const caseReducer = actionsMap[type];

            if(caseReducer) {
                return caseReducer(draft, payload);
            }

            return draft;
        });
    }
}
export {createNextState, combineReducers};

Dan contoh aplikasi todo wajib:

import {configureStore, createReducer} from "./configureStore";

const ADD_TODO = "ADD_TODO";
const TOGGLE_TODO = "TOGGLE_TODO";
const SET_VISIBILITY_FILTER = "SET_VISIBILITY_FILTER";

function setVisibility(state, newFilterType) {
    return newFilterType;
}

const visibilityReducer = createReducer("SHOW_ALL", {
    [SET_VISIBILITY_FILTER] : setVisibility
});


function addTodo(state, newTodo) {
    state.push({...newTodo, completed : false});
}

function toggleTodo(state, payload) {
    const {index} = payload;

    const todo = state[index];
    todo.completed = !todo.completed;
}

const todosReducer = createReducer([], {
    [ADD_TODO] : addTodo,
    [TOGGLE_TODO] : toggleTodo
});


const preloadedState = {
    todos: [{
        text: 'Eat food',
        completed: true
    }, {
        text: 'Exercise',
        completed: false
    }],
    visibilityFilter : 'SHOW_COMPLETED'
};


const store = configureStore({
    reducer : {
        todos : todosReducer,
        visibilityFilter : visibilityReducer,
    },
    preloadedState,
});

const exercise1 = store.getState().todos[1];

store.dispatch({type : "TOGGLE_TODO", payload : {index : 1}});

const exercise2 = store.getState().todos[1];

console.log("Same object: ", exercise1 === exercise2);

store.dispatch({type : "SET_VISIBILITY_FILTER", payload : "SHOW_COMPLETED"});

console.log(store.getState());

Saya pikir ini adalah awal yang solid dan awal yang bagus untuk lib yang sedang dibahas di utas ini. Ini mencakup poin 1,2,3, dan 6 dari daftar fitur yang saya inginkan di atas.

Iterasi di atas ini akan bagus, tapi ini adalah dasar yang kuat.

Daripada fokus pada implementasi, saya ingin kita fokus pada DX. Apa itu ekspor/API dan bagaimana penggunaannya? Saya pikir ini adalah kesempatan besar untuk melewati hanya konfigurasi dan juga melihat bagaimana orang menggunakan toko. Beberapa ide acak:

Pasangan Peredam/Aksi yang lebih mudah:

Jadikan sangat mudah untuk memasangkan reduksi dan tindakan Anda bersama dengan output statusnya. Ini kasar, tapi inilah ide dasarnya:

import { createStore, createActionPack, combineActionPacks } from 'redux/starter'

const counter = createActionPack({
  increment: counter => counter + 1,
  decrement: counter => counter - 1,
  set: (_, value) => value
}, 0)

const posts = createActionPack({
  load: async () => await fetch('/posts'),
  create: async (state, text) => state.push(await fetch('/posts/new', { body: { text } }))
}, [])

const store = createStore(
  combineActionPacks(
    counter,
    posts
  )
)

store.dispatch(counter.increment())
store.dispatch(counter.set(42))

await store.dispatch(posts.load())
await store.dispatch(posts.create('First!'))

Toko Singleton

Yang ini saya tidak dijual dengan cara apa pun, tetapi saya berpikir kembali ke hari-hari ketika kami memiliki sejarah lajang di React Router. Itu tidak sempurna, tetapi memberikan beberapa nilai.

import { store, configureStore } from 'redux/starter'

configureStore(reducer, middleware, initialState)

store.dispatch(someAction())
store.getState()

Dapat dikonfigurasi melalui import

Saya akan menyimpan paling aneh saya untuk yang terakhir. Tetapi bagaimana jika kita mengizinkan konfigurasi dengan mengimpor file. Kami membutuhkan beberapa di belakang layar lewat global, yang menjadi berantakan/merepotkan. Tapi sekali lagi, fokusnya adalah pada pengguna, bukan pada pihak kita.

import { createStore } from 'redux/starter'
import 'redux/starter/devtools'
import 'redux/starter/logger'
import 'redux/starter/immutable'

// OR!

import { createStore } from 'redux/starter/developer'
import { createStore } from 'redux/starter/production'

Untuk contoh kedua itu, saya dapat melihat pengguna melakukan alias ke paket itu di alat build mereka atau melakukan sesuatu seperti yang dilakukan React .

Oke, itu saja dari saya untuk saat ini. Sekali lagi, saya ingin memikirkan pengguna-pertama. Apa pun peretasan kotor dan jelek yang harus kita lakukan untuk menerapkan ini tidak relevan. Intinya adalah DX yang hebat dengan lebih sedikit kode yang ditulis dan lebih sedikit konfigurasi yang diperlukan.

Cintai ide-ide ini sejauh ini. Satu-satunya harapan saya untuk apa pun ini ternyata adalah akses yang anggun ke tingkat yang lebih rendah, api Redux standar. Perlu ada jalur alami bagi orang untuk menyesuaikan atau mengeluarkan. Apakah itu dalam beberapa hari, atau satu atau dua tahun, itu harus sederhana. Lock-in adalah salah satu masalah yang saya lihat (dari upaya saya sendiri dengan Jumpstate dan dari perpustakaan yang lebih baru seperti Rematch). Semakin banyak yang bisa kita hindari, semakin enak rasanya di mulut orang :)

Ya, saya telah melihat beberapa util lib yang melakukan hal-hal seperti "paket tindakan" (setidaknya sejauh aspek "tulis beberapa reduksi, ubah kunci menjadi tipe tindakan dan pembuat tindakan"), dan saya sedang mempertimbangkan untuk melempar itu sebagai item tambahan - hanya belum sampai di sana. Tidak yakin tentang aspek "combineActionPack".

Ada beberapa diskusi tambahan dengan @hswolff tadi malam. Saya ingin mempertimbangkan untuk menambahkan/mengekspor ulang pustaka pemilih , yang tampaknya merupakan superset dari Reselect API dengan beberapa manfaat tambahan yang bermanfaat:

import createSelector from 'selectorator';

// selector created with single method call
const getBarBaz = createSelector(['foo.bar', 'baz'], (bar, baz) => {
  return `${bar} ${baz}`;
});

Itu akan membantu mengurangi banyak pemilih "input sederhana" yang ditulis tangan, seperti const selectTodos = state => state.todos .

Saya tidak yakin saya melihat manfaat dari menambahkan perpustakaan pemilih. Kami juga harus memberikan beberapa pendapat tentang bentuk negara yang dimungkinkan olehnya.

Setidaknya sebagian hanya jadi ada satu item lebih sedikit yang harus dipasang pengguna ke package.json .

Saya pikir perpustakaan pemilih akan luar biasa.

Juga relevan: artikel terbaru tentang apollo-boost starter kit

Jika kita dapat memperluas react-redux 's connect 's API untuk menggunakan pemilihan ulang (atau pustaka pemilih serupa) ketika mapStateToProps adalah Array , kita dapat mendorong penggunaan penyeleksi dan membuatnya sangat nyaman tanpa merusak kompatibilitas. Saya tidak berpikir perpustakaan ini harus digabungkan dengan React atau react-redux tentu saja, tetapi mungkin kita dapat menangani ekstensibilitas itu melalui opsi untuk react-redux atau menyediakan paket lain yang membungkus starter kit dengan react-redux dukungan.

Ya, saya tidak ingin melakukan apa pun dengan React-Redux untuk MVP awal ini.

Dalam hal ini apakah ada cara yang baik untuk menambahkan abstraksi untuk penyeleksi di tingkat Redux atau apakah ini sesuatu yang hanya dapat kita lakukan secara efektif di atas reaksi-redux? Masalahnya adalah kita tidak ingin ini menjadi tidak kompatibel dengan react-redux, jadi saya kira jika itu tidak mungkin kita harus membuang pemilih untuk saat ini.

Selama itu mengimplementasikan API toko, maka itu kompatibel dengan react-redux. Kami tidak ingin merusak API itu, hanya meningkatkan DX.

Itu masuk akal. Saya belum pernah menggunakan penyeleksi di luar react-redux jadi saya bertanya-tanya apakah itu berlaku untuk mengonfigurasi Redux sendiri di sini.

@timdorr +1 pada keinginan yang diungkapkan dengan pasangan peredam/aksi yang lebih mudah. Saya juga ingin memperkenalkan beberapa cara untuk mempermudah pembuatan modul redux (alias pola bebek) sehingga membuat peredam, pembuat tindakan, dan penyeleksi adalah pengalaman yang jauh lebih menyenangkan dan lebih mudah digunakan.

Saya pikir menemukan solusi untuk masalah itu yang membuat sebagian besar orang bahagia akan membutuhkan sedikit lebih banyak pelepasan sepeda dan saya bertanya-tanya apakah itu sesuatu yang dapat kita tambahkan dalam versi tindak lanjut sehingga tidak menghalangi awal melepaskan.

Saya pikir apa yang dibuat @markerikson dalam komentarnya sudah mengurangi banyak boilerplate dan akan menjadi pra-rilis awal yang bagus.

Setelah itu, kita dapat mengatasi aspek lain dari Redux yang rumit (pembuatan redux/action/selector).

Saya pikir mencoba menyelesaikan semua masalah di depan akan menghalangi kemajuan nyata dalam bentuk apa pun.

Jika Anda pikir itu sudah cukup siap, saya pikir itu akan menjadi ide yang baik untuk memulai repositori sehingga kita dapat menguji pengaturan ini dengan kode contoh dan dogfood sedikit (atau mungkin sebuah paket di cabang fitur monorepo, dan kita bisa berkolaborasi melalui PR).

Tentu. Saya akan melihat apakah saya bisa menyiapkan sesuatu nanti hari ini.

Kami tidak membutuhkan repositori lain. Ini akan ada dalam yang sekarang. Tolong jadikan apapun sebagai PR terlebih dahulu.

Haruskah ini menjadi bagian dari paket redux sebagai impor terpisah (jadi ini sepenuhnya kompatibel kembali) atau apakah Anda lebih suka monorepo dengan beberapa paket? Saya pikir yang pertama sudah cukup, kita selalu bisa menggunakan ekspor file lain tanpa membuat paket baru jika terlalu besar.

Saya agak ingin bermain-main dengan ini sebagai repo/paket terpisah untuk memulai, sungguh.

Mungkin lebih mudah untuk menggunakan pengaturan perkakas yang ada di repo ini karena menggabungkannya kembali di masa mendatang bisa rawan kesalahan. Kami juga mungkin tidak memerlukan dukungan sintaks yang berbeda karena kami tidak membuat React ini spesifik.

Jika itu akan menjadi satu file tunggal dengan beberapa pra-konfigurasi, maka menyimpannya di sini akan lebih mudah. Karena ketergantungan, itu harus menjadi paket terpisah. Kami tidak ingin membebani aplikasi yang ada dengan itu.

Sekali lagi, saya rasa kita tidak perlu menggunakan monorepo, tetapi kita dapat memiliki folder untuk paket build tertentu jika kita mulai membuat lebih dari satu. Hanya folder starter untuk saat ini dengan package.json sendiri harus melakukan triknya.

Saya menyukai gagasan untuk menyimpan lokal ini ke paket redux utama jika hanya menggunakan kode lokal untuk redux itu sendiri. Saya menjadi lebih ragu jika kita mulai menarik ketergantungan eksternal untuk mendukung ide-ide yang diungkapkan di sini.

Saya pikir beberapa dependensi eksternal seperti immer, thunk/promise/saga, dan reselect akan sangat berharga untuk tujuan kami di sini dan sepadan dengan dependensi tambahan untuk pemula, meskipun kami mungkin tidak menginginkan dependensi tersebut pada paket redux itu sendiri .

Jadi, uh... Aku pergi dan melakukan sesuatu:

Hal-hal yang berbeda dari cuplikan tadi:

  • Saya memasukkan opsi konfigurasi enhancers , hanya karena
  • Saya menambahkan ketergantungan selectorator dan mengekspor createSelector

Pikiran?

Sebagai seseorang yang baru belajar Redux (dan React) dalam beberapa minggu terakhir, saya tidak sabar untuk melihat produk akhirnya. Saya yakin saya akan memiliki banyak hal untuk dibersihkan dalam kode saya.

👍

Jadi, selama idenya adalah menyederhanakan penggunaan redux, saya dapat mengusulkan 2 momen:

  1. Tambahkan fungsi build-in ke expect(mapStateToProps(state)).toEqual(mapStateToProps(state)) . Hanya untuk mendorong orang membuat kode yang lebih baik. Saya tidak pernah melihat tes seperti ini, tetapi _not-very-pure_ mapStateToProps adalah salah satu masalah redux.

  2. Pertimbangkan adopsi sesuatu seperti memoize-state . Ini seperti Immer.js untuk penyeleksi. Poin kuncinya - pelanggan cukup menulis mapStateToProps atau pemilih dalam bentuk yang diinginkannya, dan membuatnya menjadi memo. Bahkan dapat menyelesaikan masalah pemilihan ulang ini dengan "Berbagi Pemilih dengan Alat Peraga di Beberapa Instans Komponen" tanpa kehilangan memoisasi "umum" di antara instans. Hanya menggandakan memoize barang-barang itu

  1. Saya mengerti apa yang Anda maksud dalam hal merekomendasikan pemilih murni, tetapi pemilih idempoten yang tidak murni masih bisa lulus tes itu. Saya lebih suka saran kedua.
  2. Kedengarannya keren, jadi kita hanya membungkus selektor dengan cara yang sama seperti kita membungkus reduksi untuk immer, bukan?

Namun, seperti yang telah kita bahas di atas, ini lebih merupakan hal yang bereaksi-redux daripada sesuatu yang ada dalam paket starter yang agnostik terhadap React.

Ini benar-benar keren!

Saya punya satu permintaan / sedikit umpan balik; Saya lebih suka jika Immer tidak digunakan secara implisit.

Immer itu hebat . Ini menjadi salah satu utilitas favorit saya. Tetapi bahkan ketika menggunakannya secara eksplisit ( produce(baseState, draftState => ... ), saya khawatir ketika orang lain yang tidak terbiasa dengannya melihat kode saya, dan tidak menyadari bahwa saya hanya dapat melakukan hal-hal mutatif ini karena kekuatan super Immer.

Cara API terlihat sekarang, saya bisa membayangkan pendatang baru tidak menyadari bahwa status redux seharusnya tidak berubah. Saya pikir kesalahpahaman akan menggigit mereka ketika mereka mencoba dan menggunakan Redux tanpa starter kit ini.

Saya melihat bahwa createNextState sudah menjadi ekspor, jadi mengapa tidak mendorong pengguna untuk menggunakannya secara eksplisit:

import {createReducer, createNextState} from "@acemarke/redux-starter-kit";

function addTodo(state, newTodo) {
    return createNextState(state, draftState => {
        draftState.push({...newTodo, completed : false});
    });
}

(maaf jika saya salah memahami bagaimana createNextState dimaksudkan untuk digunakan! Belum menggali sama sekali)

Lihat https://github.com/markerikson/redux-starter-kit/issues/5.

Cara API terlihat sekarang, saya bisa membayangkan pendatang baru tidak menyadari bahwa status redux seharusnya tidak berubah. Saya pikir kesalahpahaman akan menggigit mereka ketika mereka mencoba dan menggunakan Redux tanpa starter kit ini.

Menurut pendapat saya, kami harus merekomendasikan untuk tidak menggunakan Redux secara langsung demi paket ini ketika sudah selesai karena https://github.com/reactjs/redux/issues/2858. Pada dasarnya kami ingin memperingatkan atau melindungi pengguna dari semua mutasi secara default, tetapi kami tidak dapat dengan mudah melakukan ini di inti tanpa merusak banyak hal, jadi kami harus merekomendasikan untuk tidak menggunakan inti kecuali dalam kasus tepi di mana starter kit tidak memadai. Ini mirip dengan bagaimana React merekomendasikan CRA dan Redux merekomendasikan react-redux saat menggunakan React.

Saya melihat bahwa createNextState sudah menjadi ekspor, jadi mengapa tidak mendorong pengguna untuk menggunakannya secara eksplisit:

Bukan ide yang buruk, tapi saya pikir kami lebih memilih implisit di sini terutama karena kami tidak membuat kode sumber dan penambahan immer kompatibel kembali.

Saya melihat banyak orang merekomendasikan untuk menggunakan libs seperti immer.js , yang menurut pendapat sederhana saya terdiri dari tanpa disadari menyimpang dari motivasi belajar dan menghormati persyaratan store .

Kita semua tahu bahwa toko tidak dapat dimutasi, jadi, saya lebih suka memiliki mekanisme validasi di mana ia memeriksa instance newState terhadap ( === ) previousState dan jika itu adalah contoh yang sama, buat kesalahan.

Dengan cara ini semua orang akan dipaksa untuk mempelajari aturan dan persyaratan store .

PS: Saya benar-benar memahami manfaat immer dan saya sama sekali tidak menentangnya, tetapi kami mencapai saat di mana orang akhirnya memahami konsepnya, itu akan menghasilkan sumber kebingungan yang besar, dan secara teknis mengatakan, jika kita membandingkannya, kita tidak akan melakukan apa-apa selain menambahkan lapisan kerumitan tambahan hanya untuk melonggarkan perpustakaan.

Saran Pribadi:

logger , devTools dan Thunk harus ditambahkan sebagai default dari Starter , sisanya saya percaya lebih merupakan pilihan pribadi.

Kita semua tahu bahwa toko tidak dapat dimutasi, oleh karena itu, saya lebih suka memiliki mekanisme validasi di mana ia memeriksa instance newState terhadap ( === ) sebelumnyaState dan jika itu adalah instance yang sama membuat kesalahan.

Ada kasus di mana tergantung pada tindakan yang Anda tidak ingin statusnya berubah, jadi Anda akan mengembalikan instance toko yang sama untuk menghemat memori dan mencegah perbedaan positif palsu. Bahkan jika kami mengatasi masalah ini, sepertinya Redux tidak menginginkan validator di inti dan saya pikir Immer adalah perlindungan yang baik untuk ini secara pribadi. Saya setuju bahwa itu agak mengalahkan tujuan mempelajari Redux sampai batas tertentu, tetapi saya melihat begitu banyak pengembang mempelajari Redux yang tidak ingin mempelajari FP murni atau tidak menyadarinya.

jika kita membandingkannya, kita tidak akan melakukan apa-apa selain menambahkan lapisan kompleksitas tambahan hanya untuk melonggarkan perpustakaan.

Sejauh yang saya ketahui, cara Immer mengimplementasikan Proxy hanya memiliki overhead kinerja jika itu benar-benar bermutasi, jadi pengurang pembaruan yang tidak dapat diubah seharusnya tidak memiliki overhead kinerja. Saya pikir ini adalah keseimbangan yang baik-baik saja.

Logger, devTools dan Thunk harus ditambahkan sebagai default Starter, sisanya saya percaya lebih merupakan pilihan pribadi.

Ada beberapa hal lain yang ingin saya pertimbangkan untuk dihapus (walaupun saya pribadi tidak melihat keuntungan besar bagi logger atas alat pengembang yang menggantikan overhead kinerjanya), lihat https://github.com/markerikson/ redux-starter-kit/issues/19. Namun saya tidak menentang menambahkan lebih banyak hal jika mereka kembali kompatibel seperti penggunaan Immer dan Thunk kami saat ini.

Ada kasus di mana tergantung pada tindakan yang Anda tidak ingin statusnya berubah, jadi Anda akan mengembalikan instance toko yang sama untuk menghemat memori dan mencegah perbedaan positif palsu. Bahkan jika kami mengatasi masalah ini, sepertinya Redux tidak menginginkan validator di inti dan saya pikir Immer adalah perlindungan yang baik untuk ini secara pribadi. Saya setuju bahwa itu agak mengalahkan tujuan mempelajari Redux sampai batas tertentu, tetapi saya melihat begitu banyak pengembang mempelajari Redux yang tidak ingin mempelajari FP murni atau tidak menyadarinya.

@nickmccurdy Saya benar-benar mengerti sudut pandang Anda, dan saya setuju bahwa kita tidak boleh mengalami hambatan belajar karena beberapa konsep FP, Mutasi, dan lain-lain ... Tetapi sebagai seorang pendidik saya sangat percaya untuk tidak melapisi murid dengan menyembunyikan kerumitan dari mereka. Bagaimanapun, ini hanya masalah selera, saya pro pembelajaran dan forwardness, dan melihat proposal ini, entah bagaimana insting saya memberi tahu saya bahwa kami akan bergerak maju dengan penerimaan, tetapi mundur dengan standar. Sebagai catatan, pikirkan semua konten di web saat ini yang mengajarkan Standar Redux dan bagaimana akhirnya.

Sejauh yang saya ketahui, cara Immer mengimplementasikan Proxy hanya memiliki overhead kinerja jika itu benar-benar bermutasi, jadi pengurang pembaruan yang tidak dapat diubah seharusnya tidak memiliki overhead kinerja. Saya pikir ini adalah keseimbangan yang baik-baik saja.

Ketika saya bermaksud menambahkan lapisan kompleksitas, maksud saya Immer belum pernah ada dan sekarang mungkin, kita harus mendukungnya di perpustakaan, menguji, mengevaluasi masalah kinerja dan yang terakhir tetapi tidak kalah pentingnya bagian ini di sini, membuat saya khawatir:

Immer.js - Pembekuan otomatis
Immer secara otomatis membekukan pohon status apa pun yang dimodifikasi menggunakan produk. Ini melindungi dari modifikasi yang tidak disengaja dari pohon keadaan di luar produser. Ini datang dengan dampak kinerja, jadi disarankan untuk menonaktifkan opsi ini dalam produksi. Ini secara default diaktifkan. Secara default diaktifkan selama pengembangan lokal, dan dimatikan dalam produksi. Gunakan setAutoFreeze(true / false) untuk mengaktifkan atau menonaktifkan fitur ini secara eksplisit.

Dan tiba-tiba sekarang kita juga perlu mendukung fitur yang ditambahkan di Development / Prod . Ini hanya jumlah pekerjaan yang baik dan mengkhawatirkan karena tidak banyak yang harus ditukar, tetapi sekali lagi, ini hanya pendapat pribadi saya.

@codedavinci : inti dari perpustakaan redux-starter-kit ini adalah untuk menambahkan alat dan abstraksi yang berguna di atas proses penyiapan toko Redux "dasar". Juga, perhatikan bahwa ini _tidak_ masuk ke inti Redux itu sendiri, melainkan ke perpustakaan terpisah yang pada akhirnya akan kami jadikan bagian "resmi" dari organisasi Redux.

Semua kode Redux Anda yang ada akan berfungsi. Semua tutorial yang ada akan tetap baik-baik saja. Kami hanya mencoba menambahkan pendekatan sederhana yang didukung secara resmi untuk menyiapkan dan menggunakan Redux.

@markerikson Saya mengerti tujuan memiliki starter kit dan saya sepenuhnya kecewa dengan semua yang disebutkan di atas, hanya sedikit menolak memiliki lib seperti Immer.js yang mengubah konsep, perpustakaan, orang pada akhirnya akan mempelajari starter-kit pola dan sepenuhnya mengabaikan konsep inti. Tidak ada mutasi toko adalah moto, Redux selalu menjualnya, itu bagian dari merek.

PS: Saya sepenuhnya mengerti bahwa Immer.js tidak mengubah apa pun, tetapi membantu Anda untuk tidak, saya hanya dan hanya berbicara tentang standar sintaksis yang diizinkan seperti push , splice ...

Mungkin, hanya diriku yang resisten terhadap perubahan :)

@codedavinci : ya, saya mengerti maksud kekhawatirannya. Namun, salah satu keluhan umum tentang Redux adalah kesulitan menulis kode pembaruan abadi yang tepat, dan Immer hanyalah perpustakaan terbaik yang pernah saya lihat untuk menyederhanakan pembaruan tersebut.

@markerikson , saya benar-benar menggali immer dan saya perhatikan itu sangat ringan, sederhana dan efisien. Saya benar-benar dijual :) .

Repo mana yang Anda rancang? itu:

https://github.com/markerikson/redux-starter-kit
https://www.npmjs.com/package/@acemarke/redux -starter-kit
https://unpkg.com/@acemarke/redux [email protected]/

Ya, itu saja.

@nickmccurdy memiliki banyak PR yang menunggu diskusi dan merger, sebagian besar seputar perkakas, tetapi juga beberapa diskusi tentang bagaimana kami ingin memfokuskan proyek dalam jangka panjang. Saya perlu berkeliling untuk melihat itu, tetapi telah sibuk dengan hal-hal lain selama beberapa minggu terakhir (termasuk ceramah konferensi yang saya berikan besok).

Kemajuan luar biasa @nickmccurdy & @markerikson 👍 Saya suka kesederhanaan dan efektivitasnya. @nickmccurdy memperhatikan Anda sangat aktif dalam proyek ini, saya ingin mengobrol dengan Anda tentang beberapa ide, beri tahu saya jika Anda siap untuk itu! :)

Tentu terima kasih, mungkin yang terbaik untuk memulai diskusi terbuka dalam masalah baru tetapi Anda dapat menghubungi saya secara langsung melalui [email protected] atau di Discord.

+1 untuk memisahkan combineReducers . Saya menggunakannya untuk waktu yang lama dan karena jika itu saya tidak benar-benar berpikir secara mendalam tentang bagaimana toko saya beroperasi.

Saat ini saya ingin mengatur fungsi peredam saya di sepanjang baris:

function reducer(prevState, event, handledNavigation = false) {
  if (event.type === 'NAVIGATION' && !handledNavigation) {
    return reducer(onNavigate(prevState, event), event, true);
  }

  const pageReducer = pageReducers[prevState.activePage];

  const nextSessionState = sessionReducer(prevState.sessionState, event);
  const nextPageState = pageReducer(prevState.pageState, nextSessionState, event);

  return {
    activePage: prevState.activePage,
    pageState: nextPageState,
    sessionState: nextSessionState,
  };
}

Yang merupakan sesuatu yang tidak diizinkan oleh combineReducers untuk saya lakukan.

@abradley2 : kami tidak berencana untuk menghapus combineReducers dari inti Redux, jika itu yang Anda minta. Tapi ya, kami selalu mengatakan bahwa combineReducers adalah utilitas untuk kasus penggunaan yang paling umum, dan Anda dianjurkan untuk menulis logika peredam khusus untuk situasi Anda sendiri.

Kami mendapatkan redux-starter-kit package name , dan repo telah dipindahkan ke org di https://github.com/reduxjs/redux-starter-kit . Akan menutup utas ini. Diskusi lebih lanjut dapat terjadi di repo itu.

Juga, saya mulai bekerja untuk menambahkan pemeriksaan mutasi dan serializability secara default.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat