Làm cách nào để tự động tải giảm tốc để tách mã trong ứng dụng Redux?


187

Tôi sẽ chuyển sang Redux.

Ứng dụng của tôi bao gồm rất nhiều phần (trang, thành phần) vì vậy tôi muốn tạo ra nhiều bộ giảm tốc. Các ví dụ Redux cho thấy rằng tôi nên sử dụng combineReducers()để tạo một bộ giảm tốc.

Ngoài ra, theo tôi hiểu, ứng dụng Redux nên có một cửa hàng và nó được tạo khi ứng dụng bắt đầu. Khi cửa hàng đang được tạo, tôi nên vượt qua bộ giảm tốc kết hợp của mình. Điều này có ý nghĩa nếu ứng dụng không quá lớn.

Nhưng nếu tôi xây dựng nhiều gói JavaScript thì sao? Ví dụ, mỗi trang của ứng dụng có gói riêng. Tôi nghĩ rằng trong trường hợp này, một bộ giảm tốc kết hợp là không tốt. Tôi đã xem qua các nguồn của Redux và tôi đã tìm thấy replaceReducer()chức năng. Nó dường như là những gì tôi muốn.

Tôi có thể tạo bộ giảm tốc kết hợp cho từng phần ứng dụng của mình và sử dụng replaceReducer() khi tôi di chuyển giữa các phần của ứng dụng.

Đây có phải là một cách tiếp cận tốt?

Câu trả lời:


245

Cập nhật: xem thêm cách Twitter thực hiện .

Đây không phải là một câu trả lời đầy đủ nhưng sẽ giúp bạn bắt đầu. Lưu ý rằng tôi sẽ không vứt bỏ bộ giảm tốc cũ. Tôi chỉ thêm những bộ giảm tốc mới vào danh sách kết hợp. Tôi thấy không có lý do gì để vứt bỏ bộ giảm tốc cũ ngay cả trong ứng dụng lớn nhất mà bạn không có hàng ngàn mô-đun động, đó là điểm mà bạn có thể muốn ngắt kết nối một số bộ giảm tốc trong ứng dụng của mình.

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

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

  // ...
}

Có thể có cách diễn đạt gọn gàng hơn này, tôi chỉ thể hiện ý tưởng.


13
Tôi rất thích thấy loại chức năng này được thêm vào dự án. Khả năng thêm bộ giảm tốc một cách linh hoạt là điều bắt buộc khi xử lý phân tách mã và các ứng dụng lớn. Tôi có toàn bộ các cây con có thể không được truy cập bởi một số người dùng và tải tất cả các bộ giảm tốc là một sự lãng phí. Ngay cả với các ứng dụng lớn bỏ qua redux có thể thực sự xếp chồng các bộ giảm tốc.
JeffBaumgardt

2
Đôi khi, đó là một sự lãng phí lớn hơn để 'tối ưu hóa' một cái gì đó không quan trọng.
XML

1
Hy vọng rằng nhận xét trên có ý nghĩa ... khi tôi hết phòng. Nhưng về cơ bản, tôi không thấy một cách dễ dàng để kết hợp các bộ giảm tốc khi vào một nhánh duy nhất trên cây trạng thái của chúng khi chúng được tải động từ các tuyến khác nhau /homepagevà sau đó nhiều nhánh đó được tải khi người dùng đi đến profile.Ví dụ về cách để làm điều này, sẽ là tuyệt vời. Nếu không, tôi có một thời gian khó khăn để làm phẳng cây nhà nước của tôi hoặc tôi phải có tên chi nhánh rất cụ thể user-permissionsuser-personal
BryceHayden

1
Và tôi nên hành động như thế nào, nếu tôi có trạng thái ban đầu?
Stalso

3
github.com/mxstbr/react-boiler khắc nồi hơi sử dụng kỹ thuật chính xác tương tự được đề cập ở đây để giảm tải.
Pouya Sanooei

25

Đây là cách tôi triển khai nó trong một ứng dụng hiện tại (dựa trên mã của Dan từ vấn đề GitHub!)

// 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
  }
}

Tạo một cá thể đăng ký khi bootstrapping ứng dụng của bạn, chuyển qua các bộ giảm tốc sẽ được bao gồm trong gói mục nhập:

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

Sau đó, khi định cấu hình cửa hàng và tuyến đường, hãy sử dụng chức năng mà bạn có thể cung cấp cho sổ đăng ký giảm tốc để:

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

Trường hợp các chức năng này trông giống như:

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
}

Đây là một ví dụ trực tiếp cơ bản được tạo với thiết lập này và nguồn của nó:

Nó cũng bao gồm các cấu hình cần thiết để cho phép tải lại nóng cho tất cả các bộ giảm tốc của bạn.


Cảm ơn @jonny, chỉ cần ngẩng cao đầu, ví dụ hiện đang gây ra lỗi.
Jason J. Nathan

Khai báo createdReducer () bị thiếu trong câu trả lời của bạn (Tôi biết đó là câu trả lời của Dan Abrahamov nhưng tôi nghĩ bao gồm nó sẽ tránh nhầm lẫn)
Packet Tracer

6

Hiện tại có một mô-đun bổ sung các bộ giảm tốc tiêm vào cửa hàng redux. Nó được gọi là Redux Injection .

Đây là cách sử dụng nó:

  1. Không kết hợp giảm tốc. Thay vào đó, đặt chúng vào một đối tượng (lồng nhau) của các hàm như bình thường nhưng không kết hợp chúng.

  2. Sử dụng createInjectStore từ redux-kim phun thay vì createdStore từ redux.

  3. Tiêm thuốc giảm tốc mới bằng thuốc tiêm.

Đây là một ví dụ:

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

Tiết lộ đầy đủ: Tôi là người tạo ra mô-đun.


4

Kể từ tháng 10 năm 2017:

  • Sậy

    thực hiện những gì Dan đề xuất và không có gì hơn, mà không cần chạm vào cửa hàng, dự án hoặc thói quen của bạn

Cũng có những thư viện khác nhưng chúng có thể có quá nhiều phụ thuộc, ít ví dụ, sử dụng phức tạp, không tương thích với một số phần mềm trung gian hoặc yêu cầu bạn viết lại quản lý trạng thái của mình. Sao chép từ trang giới thiệu của Reedux:


2

Chúng tôi đã phát hành một thư viện mới giúp điều chỉnh ứng dụng Redux và cho phép tự động thêm / xóa Reducers và phần mềm trung gian.

Vui lòng xem tại https://github.com/Microsoft/redux-dynamic-modules

Các mô-đun cung cấp các lợi ích sau:

  • Các mô-đun có thể dễ dàng được sử dụng lại trên ứng dụng hoặc giữa nhiều ứng dụng tương tự.

  • Các thành phần khai báo các mô-đun cần thiết cho chúng và các mô-đun redux-động đảm bảo rằng mô-đun được tải cho thành phần.

  • Các mô-đun có thể được thêm / xóa khỏi cửa hàng một cách linh hoạt, ví dụ. khi một thành phần gắn kết hoặc khi người dùng thực hiện một hành động

Đặc trưng

  • Nhóm các bộ giảm tốc, phần mềm trung gian và trạng thái thành một mô-đun duy nhất, có thể sử dụng lại.
  • Thêm và xóa các mô-đun khỏi cửa hàng Redux bất cứ lúc nào.
  • Sử dụng thành phần đi kèm để tự động thêm mô-đun khi kết xuất thành phần
  • Các tiện ích mở rộng cung cấp tích hợp với các thư viện phổ biến, bao gồm redux-saga và redux-có thể quan sát được

Kịch bản ví dụ

  • Bạn không muốn tải mã cho tất cả các bộ giảm tốc của bạn lên phía trước. Xác định một mô-đun cho một số bộ giảm tốc và sử dụng DynamicModuleLoader và một thư viện như có thể tải phản ứng để tải xuống và thêm mô-đun của bạn khi chạy.
  • Bạn có một số bộ giảm / phần mềm trung gian phổ biến cần được sử dụng lại trong các lĩnh vực khác nhau trong ứng dụng của bạn. Xác định một mô-đun và dễ dàng đưa nó vào các khu vực đó.
  • Bạn có một repo đơn có chứa nhiều ứng dụng có chung trạng thái. Tạo một gói chứa một số mô-đun và sử dụng lại chúng trên các ứng dụng của bạn

0

Dưới đây là một ví dụ khác với việc chia mã và lưu trữ redux, theo ý kiến ​​của tôi khá đơn giản và thanh lịch. Tôi nghĩ rằng nó có thể khá hữu ích cho những người đang tìm kiếm một giải pháp làm việc.

Đây lưu trữ được một chút đơn giản nó không buộc bạn phải có một không gian tên (reducer.name) trong đối tượng trạng thái của bạn, tất nhiên có thể có một vụ va chạm với những cái tên nhưng bạn có thể kiểm soát điều này bằng cách tạo ra một quy ước đặt tên cho gia giảm của bạn và nó nên ổn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.