source

Redux 애플리케이션에서 코드 분할을 위한 부하 감소기를 동적으로 로드하는 방법은 무엇입니까?

gigabyte 2022. 12. 18. 08:37
반응형

Redux 애플리케이션에서 코드 분할을 위한 부하 감소기를 동적으로 로드하는 방법은 무엇입니까?

나는 레독스로 이주할 것이다.

저의 어플리케이션은 많은 부품(페이지, 컴포넌트)으로 구성되어 있기 때문에 많은 리듀서를 만들고 싶습니다.에서는 redex를 해야 .combineReducers()1번으로 하다

또한 Redux 어플리케이션은 하나의 스토어를 가지고 있어야 하며 어플리케이션이 시작되면 생성됩니다.가게가 만들어질 때 나는 복합 환원기를 통과해야 한다.응용 프로그램이 너무 크지 않으면 이 방법이 적합합니다.

자바스크립트?예를 들어 응용 프로그램의 각 페이지에는 고유한 번들이 있습니다.이 경우 1개의 복합 환원기는 좋지 않다고 생각합니다., ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.replaceReducer() . 원하는.★★★★★★★★★★★★★★★★★」

의 각 할 수 .replaceReducer()응용 프로그램 사이를 이동할 때 사용합니다.

이게 좋은 방법인가요?

업데이트: Twitter가 어떻게 하는지 확인하세요.

이것은 완전한 답은 아니지만 시작하는 데 도움이 될 것입니다.오래된 환원제를 버리는아니라조합 목록에 새로 추가하는 중입니다.오래된 리듀서를 버릴 이유는 없습니다. 아무리 큰 앱이라도 수천 개의 다이내믹 모듈을 탑재할 가능성은 낮기 때문에 애플리케이션 리듀서의 접속을 끊어야 할 수도 있습니다.

리듀서.개요

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.displaces를 설정합니다.

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.displaces

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);
      })
    }
  };

  // ...
}

이것을 표현하는 더 좋은 방법이 있을 것이다.그냥 보여드리는 거예요.

현재의 앱에서는 이렇게 실장했습니다(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
}

이 셋업으로 작성된 기본적인 라이브 예와 소스를 다음에 나타냅니다.

또한 모든 리듀서에 대해 핫 새로고침을 활성화하기 위해 필요한 구성에 대해서도 설명합니다.

이제 환원기 저장소에 주입식 환원기를 추가하는 모듈이 있습니다.이것은 Redux Injector라고 불립니다.

사용 방법은 다음과 같습니다.

  1. 환원기를 함께 사용하지 마십시오.그 대신, 그것들을 조합하지 않고, 통상의 기능 오브젝트에 넣습니다.

  2. 작성 사용redex에서 createStore가 아닌 redex-injector에서 InjectStore를 실행합니다.

  3. injectReducer를 사용하여 새 환원제를 주입합니다.

다음은 예를 제시하겠습니다.

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);

완전 공개:저는 모듈의 작성자입니다.

2017년 10월 현재:

  • 리덕스

    Dan이 제안한 것을 실행하지만, 그 이상은 아닙니다.스토어, 프로젝트, 습관에 영향을 주지 않습니다.

다른 라이브러리도 있지만 의존관계가 너무 많고 예가 적으며 사용법이 복잡하며 일부 미들웨어와 호환되지 않거나 상태 관리를 다시 작성해야 할 수 있습니다.Reedux 소개 페이지에서 복사:

Redux 앱의 변조를 지원하고 Reducers 및 미들웨어를 동적으로 추가/삭제할 수 있는 새로운 라이브러리를 출시했습니다.

https://github.com/Microsoft/redux-dynamic-modules 를 봐 주세요.

모듈에는 다음과 같은 이점이 있습니다.

  • 모듈은 애플리케이션 전체 또는 여러 유사한 애플리케이션 간에 쉽게 재사용할 수 있습니다.

  • 컴포넌트는 필요한 모듈을 선언하고 redex-dynamic-modules는 컴포넌트에 모듈이 로드되도록 합니다.

  • 컴포넌트가 마운트되거나 사용자가 작업을 수행하는 등 저장소에서 모듈을 동적으로 추가/탈부착할 수 있습니다.

특징들

  • 리듀서, 미들웨어 및 상태를 재사용 가능한 단일 모듈로 그룹화합니다.
  • 언제든지 Redux 저장소에서 모듈을 추가 및 제거할 수 있습니다.
  • 포함된 구성 요소를 사용하여 구성 요소가 렌더링될 때 모듈을 자동으로 추가합니다.
  • 확장은 redex-saga 및 redex-observatible을 포함한 일반적인 라이브러리와의 통합을 제공합니다.

시나리오의 예

  • 모든 감속기의 코드를 미리 로드하고 싶지는 않을 것입니다.일부 리듀서용 모듈을 정의하고 Dynamic Module Loader와 리액트 로더블과 같은 라이브러리를 사용하여 런타임에 모듈을 다운로드하여 추가합니다.
  • 애플리케이션의 다른 영역에서 재사용해야 하는 일반적인 리듀서/미들웨어가 있습니다.모듈을 정의하고 해당 영역에 쉽게 포함할 수 있습니다.
  • 유사한 상태를 공유하는 여러 응용 프로그램을 포함하는 단일 보고가 있습니다.일부 모듈을 포함하는 패키지를 생성하여 애플리케이션 전체에서 재사용합니다.

코드 분할과 리덕스 스토어의 또 다른 예를 제시하겠습니다.제 생각에는 꽤 심플하고 우아한 것 같습니다.효과적인 솔루션을 찾고 있는 분들에게 매우 도움이 될 것이라고 생각합니다.

스토어는 조금 심플화되어 있기 때문에 상태 오브젝트에 네임스페이스(reducer.name)를 강제로 포함시키지 않습니다.물론 이름과의 충돌이 있을 수 있지만, 리듀서의 명명 규칙을 작성함으로써 제어할 수 있습니다.

다음은 제가 이를 구현하기 위해 따라온 접근법입니다.스토어 파일에는 항상 리듀서에 존재하는 스태틱 리듀서가 있으며, 필요한 컴포넌트가 장착되면 다이내믹 리듀서가 추가됩니다.

리듀서 파일

응용 프로그램에 항상 존재하는 static Reducers

const staticReducers = combineReducers({
  entities1: entities1,
});

const createReducer = (asyncReducers) => {
  return combineReducers({
    staticReducers,
    ...asyncReducers,
  });
};

export default createReducer;

스토어 파일

여기에서는 커스텀 미들웨어, 로거 등을 미들웨어 어레이로 전달하여 다음과 같이 사용할 수 있습니다.

import { createStore, applyMiddleware, compose } from "redux";
import createReducer from "./reducers";
import api from "./middlewares/api";

const middlewares = [ api, thunkMiddleware]
const middlewareEnhancer = applyMiddleware(...middlewares)
const enhancers = [middlewareEnhancer]
const composedEnhancers = composeWithDevTools(compose(...enhancers))
const store = createStore(createReducer(), composedEnhancers)

export default function configureStore() {
  // Add a dictionary to keep track of the registered async reducers
  store.asyncReducers = {};

  // Create an inject reducer function
  // This function adds the async reducer, and creates a new combined 
  // reducer
  store.injectReducer = (key, asyncReducer) => {
    store.asyncReducers[key] = asyncReducer;
    store.replaceReducer(createReducer(store.asyncReducers));
  };

  // Return the modified store
  return store;
}

export function getStore() {
  return store;
}

이제 동적으로 로드하는 컴포넌트가 있고 그 컴포넌트에 독자적인 슬라이스(리듀서)가 있을 수 있다고 가정합니다.그러면 주입 리듀서를 호출하여 기존 리듀서에 동적으로 추가할 수 있습니다.

 const Counter2 = React.lazy(() =>
    import("../counter2/counter2").then(async (module) => {
    const entities2 = await 
    import("../../../store/entities2").then((todosModule) => 
    todosModule.default);
    store.injectReducer("entities2", entities2);
      return module;
    })
  )


  <React.Suspense fallback={<div>loading...</div>}>
     <Counter2  />
  </React.Suspense>

이 컴포넌트를 장착하면 당사 스토어에 주입된 entity2를 찾을 수 있습니다.

언급URL : https://stackoverflow.com/questions/32968016/how-to-dynamically-load-reducers-for-code-splitting-in-a-redux-application

반응형