Redux एप्लिकेशन में कोड विभाजन के लिए रेड्यूसर को गतिशील रूप से कैसे लोड करें?


188

मैं Redux जा रहा हूं।

मेरे आवेदन में बहुत सारे भाग (पृष्ठ, घटक) शामिल हैं इसलिए मैं कई रिड्यूसर बनाना चाहता हूं। Redux के उदाहरण बताते हैं कि मुझे combineReducers()एक reducer उत्पन्न करने के लिए उपयोग करना चाहिए ।

जैसा कि मैं समझता हूं कि Redux एप्लिकेशन का एक स्टोर होना चाहिए और एप्लिकेशन शुरू होते ही इसे बनाया जाता है। जब स्टोर बनाया जा रहा है तो मुझे अपना संयुक्त रेड्यूसर पास करना चाहिए। यह समझ में आता है कि यदि आवेदन बहुत बड़ा नहीं है।

लेकिन क्या होगा अगर मैं एक से अधिक जावास्क्रिप्ट बंडल बनाऊं? उदाहरण के लिए, आवेदन के प्रत्येक पृष्ठ का अपना बंडल है। मुझे लगता है कि इस मामले में एक संयुक्त reducer अच्छा नहीं है। मैंने Redux के स्रोतों के माध्यम से देखा और मुझे replaceReducer()फ़ंक्शन मिल गए हैं। ऐसा लगता है कि मैं क्या चाहता हूं।

मैं अपने आवेदन के प्रत्येक भाग के लिए संयुक्त reducer बना सकता हूं और replaceReducer()जब मैं आवेदन के कुछ हिस्सों के बीच स्थानांतरित करूंगा।

क्या यह एक अच्छा तरीका है?

जवाबों:


245

अपडेट: यह भी देखें कि ट्विटर इसे कैसे करता है

यह पूर्ण उत्तर नहीं है लेकिन आपको आरंभ करने में मदद करनी चाहिए। ध्यान दें कि मैं पुराने रिड्यूसर को नहीं फेंक रहा हूं- मैं सिर्फ संयोजन सूची में नए जोड़ रहा हूं । मैं दूर पुराने reducers-भी फेंक आप गतिशील मॉड्यूल है, जो बिंदु जहां है के हजारों की संभावना नहीं कर रहे हैं सबसे बड़ा अनुप्रयोग में कोई कारण नहीं देख सकता है अपने आवेदन में कुछ reducers डिस्कनेक्ट करना चाहते हैं।

reducers.js

import { combineReducers } from 'redux';
import users from './reducers/users';
import posts from './reducers/posts';

export default function createReducer(asyncReducers) {
  return combineReducers({
    users,
    posts,
    ...asyncReducers
  });
}

store.js

import { createStore } from 'redux';
import createReducer from './reducers';

export default function configureStore(initialState) {
  const store = createStore(createReducer(), initialState);
  store.asyncReducers = {};
  return store;
}

export function injectAsyncReducer(store, name, asyncReducer) {
  store.asyncReducers[name] = asyncReducer;
  store.replaceReducer(createReducer(store.asyncReducers));
}

routes.js

import { injectAsyncReducer } from './store';

// Assuming React Router here but the principle is the same
// regardless of the library: make sure store is available
// when you want to require.ensure() your reducer so you can call
// injectAsyncReducer(store, name, reducer).

function createRoutes(store) {
  // ...

  const CommentsRoute = {
    // ...

    getComponents(location, callback) {
      require.ensure([
        './pages/Comments',
        './reducers/comments'
      ], function (require) {
        const Comments = require('./pages/Comments').default;
        const commentsReducer = require('./reducers/comments').default;

        injectAsyncReducer(store, 'comments', commentsReducer);
        callback(null, Comments);
      })
    }
  };

  // ...
}

इसे व्यक्त करने का तरीका हो सकता है - मैं सिर्फ विचार दिखा रहा हूं।


13
मैं इस प्रकार की कार्यक्षमता को परियोजना में जोड़ा जाना पसंद करूंगा। कोड बंटवारे और बड़े अनुप्रयोगों से निपटने के दौरान गतिशील रूप से रीड्यूसर जोड़ने की क्षमता आवश्यक है। मेरे पास पूरे उप पेड़ हैं जो कुछ उपयोगकर्ताओं द्वारा एक्सेस नहीं किए जा सकते हैं और सभी reducers को लोड करना एक बेकार है। Redux-अनदेखा बड़े अनुप्रयोगों के साथ भी वास्तव में reducers स्टैक कर सकते हैं।
जेफ बामगार्ड 14

2
कभी-कभी, यह कुछ असंगतता को 'अनुकूलित' करने के लिए एक बड़ा बेकार है।
एक्सएमएल

1
उम्मीद है कि उपरोक्त टिप्पणी समझ में आती है ... जैसा कि मैं कमरे से बाहर चला गया। लेकिन मूल रूप से मुझे reducers के संयुक्त होने का एक आसान तरीका नहीं दिखता है जब हमारे राज्य के पेड़ पर एक ही शाखा में जब वे गतिशील रूप से विभिन्न मार्गों से लोड होते हैं /homepageऔर फिर उस शाखा का अधिक लोड हो जाता है जब उपयोगकर्ता अपने profile.उदाहरण पर जाता है कि कैसे ऐसा करने के लिए, भयानक होगा। अन्यथा मेरे पास मेरे राज्य के पेड़ को समतल करने के लिए एक कठिन समय है या मेरे पास बहुत विशिष्ट शाखा नाम हैं user-permissionsऔरuser-personal
ब्रायहेडेन

1
और यदि मुझे प्रारंभिक अवस्था है तो मुझे कैसे कार्य करना चाहिए?
स्टाल्सो

3
github.com/mxstbr/react-boilerplate boilerplate रेड्यूसर लोड करने के लिए यहां बताए गए सटीक तकनीक का उपयोग करता है।
पूय सानुई

25

इस तरह मैंने इसे एक मौजूदा ऐप में लागू किया (एक GitHub मुद्दे से Dan द्वारा कोड के आधार पर!)

// Based on https://github.com/rackt/redux/issues/37#issue-85098222
class ReducerRegistry {
  constructor(initialReducers = {}) {
    this._reducers = {...initialReducers}
    this._emitChange = null
  }
  register(newReducers) {
    this._reducers = {...this._reducers, ...newReducers}
    if (this._emitChange != null) {
      this._emitChange(this.getReducers())
    }
  }
  getReducers() {
    return {...this._reducers}
  }
  setChangeListener(listener) {
    if (this._emitChange != null) {
      throw new Error('Can only set the listener for a ReducerRegistry once.')
    }
    this._emitChange = listener
  }
}

अपने ऐप को बूटस्ट्रैप करते समय एक रजिस्ट्री उदाहरण बनाएं, जो रिड्यूसर में गुजर रहा है जो प्रवेश बंडल में शामिल किया जाएगा:

// coreReducers is a {name: function} Object
var coreReducers = require('./reducers/core')
var reducerRegistry = new ReducerRegistry(coreReducers)

फिर स्टोर और मार्गों को कॉन्फ़िगर करते समय, एक फ़ंक्शन का उपयोग करें जिसे आप रिड्यूसर रजिस्ट्री को दे सकते हैं:

var routes = createRoutes(reducerRegistry)
var store = createStore(reducerRegistry)

जहां ये कार्य कुछ इस तरह दिखते हैं:

function createRoutes(reducerRegistry) {
  return <Route path="/" component={App}>
    <Route path="core" component={Core}/>
    <Route path="async" getComponent={(location, cb) => {
      require.ensure([], require => {
        reducerRegistry.register({async: require('./reducers/async')})
        cb(null, require('./screens/Async'))
      })
    }}/>
  </Route>
}

function createStore(reducerRegistry) {
  var rootReducer = createReducer(reducerRegistry.getReducers())
  var store = createStore(rootReducer)

  reducerRegistry.setChangeListener((reducers) => {
    store.replaceReducer(createReducer(reducers))
  })

  return store
}

यहां एक मूल लाइव उदाहरण दिया गया है जो इस सेटअप और इसके स्रोत के साथ बनाया गया था:

यह आपके सभी रेड्यूसर के लिए गर्म पुनः लोड करने में सक्षम करने के लिए आवश्यक कॉन्फ़िगरेशन को भी कवर करता है।


धन्यवाद @ जॉनी, सिर्फ एक सिर, उदाहरण अब एक त्रुटि फेंक रहा है।
जेसन जे। नाथन

createReducer () घोषणा आपके उत्तर से गायब है (मुझे पता है कि यह दान इब्राहीम के उत्तर में है, लेकिन मुझे लगता है कि यह भ्रम से बचना होगा)
पैकेट ट्रेसर

6

अब एक मॉड्यूल है जो Redux स्टोर में रिड्यूसर को इंजेक्ट करता है। इसे Redux Injector कहा जाता है ।

यहाँ इसका उपयोग कैसे किया जाता है:

  1. रेड्यूसर को संयोजित न करें। इसके बजाय आप उन्हें (nested) कार्यों के ऑब्जेक्ट के रूप में डालते हैं जैसा कि आप सामान्य रूप से लेकिन उनके संयोजन के बिना करेंगे।

  2. Redux से createStore के बजाय redux-इंजेक्टर से createInjectStore का उपयोग करें।

  3. इंजेक्टरड्यूसर के साथ नए रेड्यूसर इंजेक्ट करें।

यहाँ एक उदाहरण है:

import { createInjectStore, injectReducer } from 'redux-injector';

const reducersObject = {
   router: routerReducerFunction,
   data: {
     user: userReducerFunction,
     auth: {
       loggedIn: loggedInReducerFunction,
       loggedOut: loggedOutReducerFunction
     },
     info: infoReducerFunction
   }
 };

const initialState = {};

let store = createInjectStore(
  reducersObject,
  initialState
);

// Now you can inject reducers anywhere in the tree.
injectReducer('data.form', formReducerFunction);

पूर्ण प्रकटीकरण: मैं मॉड्यूल का निर्माता हूं।


4

अक्टूबर 2017 तक:

  • Reedux

    आपके स्टोर, आपकी परियोजना या आपकी आदतों को छूने के बिना, डैन ने जो सुझाव दिया और अधिक कुछ नहीं किया

अन्य पुस्तकालय भी हैं, लेकिन उनमें बहुत अधिक निर्भरताएं हो सकती हैं, कम उदाहरण, जटिल उपयोग, कुछ बिचौलियों के साथ असंगत हैं या आपको अपने राज्य प्रबंधन को फिर से लिखने की आवश्यकता है। रीडक्स के परिचय पृष्ठ से कॉपी किया गया:


2

हमने एक नई लाइब्रेरी जारी की जो Redux ऐप को मॉड्यूलेट करने में मदद करती है और Reducers और Middlewares को गतिशील रूप से जोड़ने / हटाने की अनुमति देती है।

कृपया https://github.com/Microsoft/redux-dynamic-modules पर एक नज़र डालें

मॉड्यूल निम्नलिखित लाभ प्रदान करते हैं:

  • मॉड्यूल आसानी से आवेदन भर में, या कई इसी तरह के अनुप्रयोगों के बीच फिर से इस्तेमाल किया जा सकता है।

  • घटक उनके द्वारा आवश्यक मॉड्यूल की घोषणा करते हैं और रीडक्स-डायनामिक-मॉड्यूल यह सुनिश्चित करते हैं कि मॉड्यूल घटक के लिए लोड किया गया है।

  • मॉड्यूल को स्टोर से गतिशील रूप से, पूर्व में जोड़ा / हटाया जा सकता है। जब एक घटक आरोहित होता है या जब कोई उपयोगकर्ता कोई क्रिया करता है

विशेषताएं

  • समूह को एक साथ रिड्यूसर, मिडलवेयर और स्टेट को एक सिंगल, री-यूजेबल मॉड्यूल में बदल दिया।
  • किसी भी समय एक Redux स्टोर से मॉड्यूल जोड़ें और निकालें।
  • किसी घटक को प्रस्तुत करने के लिए स्वचालित रूप से एक मॉड्यूल जोड़ने के लिए शामिल घटक का उपयोग करें
  • एक्सटेंशन लोकप्रिय पुस्तकालयों के साथ एकीकरण प्रदान करते हैं, जिसमें redux-saga और redux-observable शामिल हैं

उदाहरण परिदृश्य

  • आप अपने सभी रिड्यूसर के लिए कोड को लोड नहीं करना चाहते हैं। कुछ रिड्यूसर के लिए एक मॉड्यूल को परिभाषित करें और रनटाइम पर अपने मॉड्यूल को डाउनलोड करने और जोड़ने के लिए डायनामिकमॉडलूलेडर और एक लाइब्रेरी जैसे प्रतिक्रिया-लोड करने योग्य का उपयोग करें।
  • आपके पास कुछ सामान्य रीड्यूसर / मिडलवेयर हैं जिन्हें आपके एप्लिकेशन के विभिन्न क्षेत्रों में फिर से उपयोग करने की आवश्यकता है। एक मॉड्यूल को परिभाषित करें और आसानी से इसे उन क्षेत्रों में शामिल करें।
  • आपके पास एक मोनो-रेपो है जिसमें कई एप्लिकेशन शामिल हैं जो समान स्थिति साझा करते हैं। कुछ मॉड्यूल युक्त पैकेज बनाएं और उन्हें अपने अनुप्रयोगों में फिर से उपयोग करें

0

यहाँ कोड स्प्लिटिंग और रेडक्स स्टोर के साथ एक और उदाहरण है , मेरी राय में बहुत सरल और सुरुचिपूर्ण। मुझे लगता है कि यह उन लोगों के लिए काफी उपयोगी हो सकता है जो काम के समाधान की तलाश में हैं।

यह स्टोर थोड़ा सा सरलीकृत है, यह आपको अपनी राज्य वस्तु में एक नाम स्थान (reducer.name) के लिए मजबूर नहीं करता है, बेशक नामों के साथ टकराव हो सकता है, लेकिन आप अपने reducers के लिए एक नामकरण सम्मेलन बनाकर इसे नियंत्रित कर सकते हैं और यह ठीक होना चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.