私はReduxに移行します。
私のアプリケーションはたくさんのパーツ(ページ、コンポーネント)から構成されているので、たくさんのリデューサーを作りたいと思います。 Reduxの例では、1つのリデューサーを生成するためにcombineReducers()
を使用する必要があることを示しています。
また、私が理解しているように、Reduxアプリケーションは1つのストアを持つべきであり、アプリケーションの起動後に作成されます。店が作成されているとき私は私の減力剤を渡すべきである。アプリケーションがそれほど大きくない場合、これは理にかなっています。
しかし、複数のJavaScriptバンドルを作成した場合はどうなりますか?たとえば、アプリケーションの各ページには独自のバンドルがあります。この場合、一体型減速機は良くないと思います。私はReduxのソースを調べたところ、replaceReducer()
関数が見つかりました。それは私が欲しいもののようです。
私は私のアプリケーションの各部分のために結合された減力剤を作成し、私がアプリケーションの部分の間を移動するときにreplaceReducer()
を使うことができます。
これは良いアプローチですか?
更新日: Twitterのやり方 もご覧ください。
これは完全な答えではありませんが、始めるのに役立つはずです。私は古いレデューサーを捨てていないことに注意してください - 私はただ新しいものを組み合わせリストに加えています。私は古いリデューサーを捨てる理由はありません - あなたがmayにしたいポイントである最大のアプリでさえ、あなたは数千の動的モジュールを持つことはまずないでしょう。あなたのアプリケーションでいくつかの減力剤を切り離してください。
import { combineReducers } from 'redux';
import users from './reducers/users';
import posts from './reducers/posts';
export default function createReducer(asyncReducers) {
return combineReducers({
users,
posts,
...asyncReducers
});
}
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));
}
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と呼ばれています。 https://github.com/randallknutson/redux-injector
使い方は次のとおりです。
減力剤を結合しないでください。代わりに、それらを結合することなく、通常どおりに関数の(ネストされた)オブジェクトに配置します。
ReduxからのcreateStoreの代わりにredux-injectorからのcreateInjectStoreを使用してください。
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月現在:
あなたの店、あなたのプロジェクトやあなたの習慣に触れることなく、ダンが提案したことを実行します。
他のライブラリもありますが、依存関係が多すぎたり、例が少なく、使い方が複雑で、ミドルウェアと互換性がない場合や、状態管理を書き直す必要がある場合があります。 Reeduxの紹介ページからコピーしたもの:
Reduxアプリのモジュレーションを助け、Reducerやミドルウェアを動的に追加/削除することを可能にする新しいライブラリをリリースしました。
ご覧ください https://github.com/Microsoft/redux-dynamic-modules
モジュールには次のような利点があります。
モジュールは、アプリケーション全体で、または複数の同様のアプリケーション間で簡単に再利用できます。
コンポーネントはそれらが必要とするモジュールを宣言し、redux-dynamic-modulesはそのモジュールがそのコンポーネント用にロードされることを保証します。
特長
シナリオ例