webentwicklung-frage-antwort-db.com.de

Reduzieren Sie die Reduktionsreduzierer dynamisch mit dem Reaktiver Router 4

Ich teile meinen Code basierend auf Komponenten auf und möchte meine Reduktionen nur dann einspritzen, wenn eine Komponente geladen wird, anstatt sie von Anfang an im Shop zu stapeln. 

In reaktiver Router 3 war das ziemlich unkompliziert, aber ich glaube nicht, dass er mit dem reaktiven Router 4 funktioniert.

Hier sind die Reduzierstücke und der Laden:

reduzierungen.js

import { combineReducers } from 'redux'
import { routerReducer } from 'react-router-redux'

import modalReducer from '../modules/modal'

export default combineReducers({
  routing : routerReducer,
  modal   : modalReducer
})

store.js

import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'react-router-redux'
import thunk from 'redux-thunk'
import createHistory from 'history/createBrowserHistory'
import rootReducer from './reducers'

export const history = createHistory()

const initialState = {}
const enhancers = []
const middleware = [
  thunk,
  routerMiddleware(history)
]

if (process.env.NODE_ENV === 'development') {
  const devToolsExtension = window.devToolsExtension

  if (typeof devToolsExtension === 'function') {
    enhancers.Push(devToolsExtension())
  }
}

const composedEnhancers = compose(
  applyMiddleware(...middleware),
  ...enhancers
)

const store = createStore(
  rootReducer(),
  initialState,
  composedEnhancers
)
export default store

Und ich nutze Lazy Load für die Routen.

Wie implementiere ich Split Reductions?

Ich möchte die asynchrone Reduzierstücke so etwas injizieren:

function createReducer(asyncReducers) {
  return combineReducers({
    ...asyncReducers,
    system,
    router,
  })
}

function injectReducer(store, { key, reducer }) {
  if (Reflect.has(store.asyncReducers, key)) return

  store.asyncReducers[key] = reducer
  store.replaceReducer(createReducer(store.asyncReducers))
}
12
S. Schenk

Führen Sie in react-router v4 für die asynchrone Injektion von Reduzierern folgende Schritte aus:

Fügen Sie in Ihrer Datei reducer.js eine Funktion namens createReducer hinzu, die die injedReducers als Argument aufnimmt und den kombinierten Reduzierer zurückgibt:

/**
 * Creates the main reducer with the dynamically injected ones
 */
export default function createReducer(injectedReducers) {
  return combineReducers({
    route: routeReducer,
    modal: modalReducer,
    ...injectedReducers,
  });
} 

Dann in Ihrer store.js Datei, 

import createReducer from './reducers.js';

const store = createStore(
  createReducer(),
  initialState,
  composedEnhancers
);
store.injectedReducers = {}; // Reducer registry

Damit der Reduzierer auf asynchrone Weise injiziert werden kann, wenn Ihr Reaktionscontainer aktiviert wird, müssen Sie die Funktion injectReducer.js in Ihrem Container verwenden und dann alle Reduzierer zusammen mit connect ..__ zusammenstellen. Beispielkomponente Todo.js:

// example component 
import { connect } from 'react-redux';
import { compose } from 'redux';
import injectReducer from 'filepath/injectReducer';
import { addToDo, starToDo } from 'containers/Todo/reducer';

class Todo extends React.Component {
// your component code here
}
const withConnect = connect(mapStateToProps, mapDispatchToProps);

const addToDoReducer = injectReducer({
  key: 'todoList',
  reducer: addToDo,
});

const starToDoReducer = injectReducer({
  key: 'starredToDoList',
  reducer: starToDo,
});

export default compose(
  addToDoReducer,
  starToDoReducer,
  withConnect,
)(Todo);

React-Boilerplate ist eine ausgezeichnete Quelle, um die gesamte Einrichtung zu verstehen. Innerhalb von Sekunden können Sie eine Beispiel-App generieren. Der Code für injectReducer.js, configureStore.js (oder store.js in Ihrem Fall) und in Tatsächlich kann diese gesamte Konfiguration von der Reaktierkesselplatte genommen werden. Einen spezifischen Link finden Sie hier für injectReducer.js , configureStore.js

11
Anu

Um Reduktionen asynchron einzuspeisen, müssen Sie im ersten Schritt create store in dem von Ihnen genannten Format schreiben:

Reduzierungen

Bei Reduzierern besteht der einzige Unterschied darin, asyncReducers als Eingabe der createReducer-Funktion zu erhalten und auf folgende Weise für Kombinationsverringerungen zu verwenden.

function createReducer(asyncReducers) {
  return combineReducers({
    ...asyncReducers,
    system,
    router,
  })
}

Store konfigurieren

Ihre configureStore-Datei sollte wie folgt aussehen. Ich habe einige Änderungen an Ihrer Struktur vorgenommen. Zuerst habe ich Middlewares in Enhancer angewendet, um Chrome Redux DevTool Extention verwenden zu können, falls es installiert ist. Ansonsten Redux Compose verwenden (und auch den Reducer Hot-Reloader für Async-Reduktoren).

import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'react-router-redux'
import thunk from 'redux-thunk'
import createHistory from 'history/createBrowserHistory'
import rootReducer from './reducers'

export const history = createHistory()

const initialState = {}

const middleware = [
  thunk,
  routerMiddleware(history)
]

const enhancers = [
  applyMiddleware(...middlewares),
];


/* eslint-disable no-underscore-dangle */
const composeEnhancers =
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
  ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
    // TODO Try to remove when `react-router-redux` is out of beta, LOCATION_CHANGE should not be fired more than once after hot reloading
    // Prevent recomputing reducers for `replaceReducer`
    shouldHotReload: false,
  })
  : compose;
/* eslint-enable */


const store = createStore(
   rootReducer(),
   initialState,
   composeEnhancers(...enhancers)
);

// Extensions
store.injectedReducers = {}; // Reducer registry

/ Make reducers hot reloadable, see http://mxs.is/googmo
/* istanbul ignore next */
if (module.hot) {
  module.hot.accept('./reducers', () => {
    store.replaceReducer(createReducer(store.injectedReducers));
  });
}

export default store;

Komponente

Eine einfache Komponente wird so sein. Wie Sie in dieser Komponente sehen, müssen wir zuerst die connect-Komponente reagieren und dann mapStateToProps und mapDispatchToProps verwenden. Dann benötigen Sie zwei Elemente: 

1) die Reduzierdatei, 2) die Reduzierfunktion einspritzen

danach erstellen wir connect und reducerInjected mit der Komponente.

import React from 'react';
import { connect } from 'react-redux';
import { compose } from 'redux';
import reducerForThisComponent from './reducer';
import injectReducer from 'path_to_recuer_injector';

const Component = (props)=><div>Component</div>

function mapStateToProps (state){
   return {}
}
const withConnect = connect(mapStateToProps);
const withReducer = injectReducer({ key: 'login', reducerForThisComponent });

export default compose(
  withReducer,
  withConnect,
)(Component);

injectReducer.js

diese Datei kann auf viele Arten implementiert werden. Eine der Best Practices wird durch React-Boilerplate implementiert. Dies ist die Datei, die zum Einspritzen von Reduktionen in Ihre Komponenten verwendet wird. Diese Datei hat jedoch eine weitere Abhängigkeit (getInjectors.js), die neben injectReducer.js in ein Hilfsprogramm eingefügt werden kann

import React from 'react';
import PropTypes from 'prop-types';
import hoistNonReactStatics from 'hoist-non-react-statics';

import getInjectors from './getInjectors';

/**
 * Dynamically injects a reducer
 *
 * @param {string} key A key of the reducer
 * @param {function} reducer A reducer that will be injected
 *
 */
export default ({ key, reducer }) => (WrappedComponent) => {
  class ReducerInjector extends React.Component {
    static WrappedComponent = WrappedComponent;
    static contextTypes = {
      store: PropTypes.object.isRequired,
    };
    static displayName = `withReducer(${(WrappedComponent.displayName || WrappedComponent.name || 'Component')})`;

    componentWillMount() {
      const { injectReducer } = this.injectors;

      injectReducer(key, reducer);
    }

    injectors = getInjectors(this.context.store);

    render() {
      return <WrappedComponent {...this.props} />;
    }
  }

  return hoistNonReactStatics(ReducerInjector, WrappedComponent);
};

getInjectors.js

import invariant from 'invariant';
import isEmpty from 'lodash/isEmpty';
import isFunction from 'lodash/isFunction';
import isObject from 'lodash/isObject';

import isString from 'lodash/isString';

import createReducer from '../reducers'; //The createStoreFile


/**
 * Validate the shape of redux store
 */
function checkStore(store) {
  const shape = {
    dispatch: isFunction,
    subscribe: isFunction,
    getState: isFunction,
    replaceReducer: isFunction,
    runSaga: isFunction,
    injectedReducers: isObject,
    injectedSagas: isObject,
  };
  invariant(
    conformsTo(store, shape),
    '(app/utils...) injectors: Expected a valid redux store'
  );
}


export function injectReducerFactory(store, isValid) {
  return function injectReducer(key, reducer) {
    if (!isValid) checkStore(store);

    invariant(
      isString(key) && !isEmpty(key) && isFunction(reducer),
      '(app/utils...) injectReducer: Expected `reducer` to be a reducer function'
    );

    // Check `store.injectedReducers[key] === reducer` for hot reloading when a key is the same but a reducer is different
    if (Reflect.has(store.injectedReducers, key) && store.injectedReducers[key] === reducer) return;

    store.injectedReducers[key] = reducer; // eslint-disable-line no-param-reassign
    store.replaceReducer(createReducer(store.injectedReducers));
  };
}

export default function getInjectors(store) {
  checkStore(store);

  return {
    injectReducer: injectReducerFactory(store, true),
  };
}

Jetzt ist alles eingestellt. Sie haben alle Funktionen, wie zum Beispiel Reduziereinspritzung und sogar Unterstützung für heiße Modulreduzierlasten in der Entwicklungsphase. Ich schlage jedoch zwei Dinge vor:

  1. Es könnte eine gute Idee sein, sich react-boilerplate anzusehen, da es viele großartige Funktionen bietet, die mit Best Practices für große Anwendungen implementiert wurden.

  2. Wenn Sie eine Code-Aufteilung planen, bedeutet dies, dass Sie eine Anwendung mit Skalierbarkeitsproblem haben werden. Daher empfehle ich, kein Redux-Thunk und stattdessen Redux-Saga zu verwenden. Und die beste Lösung ist, Inject saga middlewares asynchronously und Sagadateien auszuwerfen, sobald die Komponente nicht mehr bereitgestellt wird. Diese Vorgehensweise kann Ihre Anwendung auf verschiedene Weise verbessern.

0

Sie können nicht nur Reduzierungen, sondern auch Sagas injizieren, Seiten mit Blöcken laden und Ihre Komponenten mit ihren eigenen CSS und Assets (Bildern, Symbolen) wirklich auf kompetente Art und Weise erstellen. Es gibt eine ganze Philosophie darüber - atomares Design , und hier ist eine Boilerplate, die eine ähnliche Idee verfolgt:

https://github.com/react-boilerplate/react-boilerplate

Ich bin mir bewusst, dass meine Antwort nicht ausreichend ist, aber es könnte mehr Anhaltspunkte für die nächsten Schritte geben.

0
sultan