From 4264c62111cd5fa3e4f940ce9d9f058dc9d9c8d4 Mon Sep 17 00:00:00 2001 From: Sorin Davidoi Date: Sun, 9 Jul 2017 12:16:08 +0200 Subject: [PATCH] refactor: Make all reducers sync (#4125) --- app/javascript/mastodon/actions/store.js | 7 ---- .../mastodon/containers/mastodon.js | 3 +- .../features/ui/util/async-components.js | 41 ++----------------- app/javascript/mastodon/reducers/compose.js | 4 +- app/javascript/mastodon/reducers/index.js | 15 +++---- .../mastodon/reducers/media_attachments.js | 4 +- .../mastodon/store/configureStore.js | 25 +---------- app/views/layouts/application.html.haml | 9 ---- 8 files changed, 18 insertions(+), 90 deletions(-) diff --git a/app/javascript/mastodon/actions/store.js b/app/javascript/mastodon/actions/store.js index 08c2810cae..efdb0771a5 100644 --- a/app/javascript/mastodon/actions/store.js +++ b/app/javascript/mastodon/actions/store.js @@ -16,10 +16,3 @@ export function hydrateStore(rawState) { state, }; }; - -export function hydrateStoreLazy(name, state) { - return { - type: `${STORE_HYDRATE_LAZY}-${name}`, - state, - }; -}; diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js index 6e79f9e4f7..87ab6023c4 100644 --- a/app/javascript/mastodon/containers/mastodon.js +++ b/app/javascript/mastodon/containers/mastodon.js @@ -23,8 +23,7 @@ const { localeData, messages } = getLocale(); addLocaleData(localeData); export const store = configureStore(); -const initialState = JSON.parse(document.getElementById('initial-state').textContent); -export const hydrateAction = hydrateStore(initialState); +const hydrateAction = hydrateStore(JSON.parse(document.getElementById('initial-state').textContent)); store.dispatch(hydrateAction); export default class Mastodon extends React.PureComponent { diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index 56880dd1f6..55de114b51 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -1,40 +1,13 @@ -import { store } from '../../../containers/mastodon'; -import { refreshNotifications } from '../../../actions/notifications'; -import { injectAsyncReducer } from '../../../store/configureStore'; - -// NOTE: When lazy-loading reducers, make sure to add them -// to application.html.haml (if the component is preloaded there) - export function EmojiPicker () { return import(/* webpackChunkName: "emojione_picker" */'emojione-picker'); } export function Compose () { - return Promise.all([ - import(/* webpackChunkName: "features/compose" */'../../compose'), - import(/* webpackChunkName: "reducers/compose" */'../../../reducers/compose'), - import(/* webpackChunkName: "reducers/media_attachments" */'../../../reducers/media_attachments'), - import(/* webpackChunkName: "reducers/search" */'../../../reducers/search'), - ]).then(([component, composeReducer, mediaAttachmentsReducer, searchReducer]) => { - injectAsyncReducer(store, 'compose', composeReducer.default); - injectAsyncReducer(store, 'media_attachments', mediaAttachmentsReducer.default); - injectAsyncReducer(store, 'search', searchReducer.default); - - return component; - }); + return import(/* webpackChunkName: "features/compose" */'../../compose'); } export function Notifications () { - return Promise.all([ - import(/* webpackChunkName: "features/notifications" */'../../notifications'), - import(/* webpackChunkName: "reducers/notifications" */'../../../reducers/notifications'), - ]).then(([component, notificationsReducer]) => { - injectAsyncReducer(store, 'notifications', notificationsReducer.default); - - store.dispatch(refreshNotifications()); - - return component; - }); + return import(/* webpackChunkName: "features/notifications" */'../../notifications'); } export function HomeTimeline () { @@ -110,15 +83,7 @@ export function MediaModal () { } export function OnboardingModal () { - return Promise.all([ - import(/* webpackChunkName: "modals/onboarding_modal" */'../components/onboarding_modal'), - import(/* webpackChunkName: "reducers/compose" */'../../../reducers/compose'), - import(/* webpackChunkName: "reducers/media_attachments" */'../../../reducers/media_attachments'), - ]).then(([component, composeReducer, mediaAttachmentsReducer]) => { - injectAsyncReducer(store, 'compose', composeReducer.default); - injectAsyncReducer(store, 'media_attachments', mediaAttachmentsReducer.default); - return component; - }); + return import(/* webpackChunkName: "modals/onboarding_modal" */'../components/onboarding_modal'); } export function VideoModal () { diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 09db95e2d7..d0b47a85c2 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -23,7 +23,7 @@ import { COMPOSE_EMOJI_INSERT, } from '../actions/compose'; import { TIMELINE_DELETE } from '../actions/timelines'; -import { STORE_HYDRATE_LAZY } from '../actions/store'; +import { STORE_HYDRATE } from '../actions/store'; import Immutable from 'immutable'; import uuid from '../uuid'; @@ -134,7 +134,7 @@ const privacyPreference = (a, b) => { export default function compose(state = initialState, action) { switch(action.type) { - case `${STORE_HYDRATE_LAZY}-compose`: + case STORE_HYDRATE: return clearAll(state.merge(action.state.get('compose'))); case COMPOSE_MOUNT: return state.set('mounted', true); diff --git a/app/javascript/mastodon/reducers/index.js b/app/javascript/mastodon/reducers/index.js index 79062f2f9c..919345f165 100644 --- a/app/javascript/mastodon/reducers/index.js +++ b/app/javascript/mastodon/reducers/index.js @@ -14,6 +14,10 @@ import status_lists from './status_lists'; import cards from './cards'; import reports from './reports'; import contexts from './contexts'; +import compose from './compose'; +import search from './search'; +import media_attachments from './media_attachments'; +import notifications from './notifications'; const reducers = { timelines, @@ -31,13 +35,10 @@ const reducers = { cards, reports, contexts, + compose, + search, + media_attachments, + notifications, }; -export function createReducer(asyncReducers) { - return combineReducers({ - ...reducers, - ...asyncReducers, - }); -} - export default combineReducers(reducers); diff --git a/app/javascript/mastodon/reducers/media_attachments.js b/app/javascript/mastodon/reducers/media_attachments.js index d17d465aa4..85bea4f0b3 100644 --- a/app/javascript/mastodon/reducers/media_attachments.js +++ b/app/javascript/mastodon/reducers/media_attachments.js @@ -1,4 +1,4 @@ -import { STORE_HYDRATE_LAZY } from '../actions/store'; +import { STORE_HYDRATE } from '../actions/store'; import Immutable from 'immutable'; const initialState = Immutable.Map({ @@ -7,7 +7,7 @@ const initialState = Immutable.Map({ export default function meta(state = initialState, action) { switch(action.type) { - case `${STORE_HYDRATE_LAZY}-media_attachments`: + case STORE_HYDRATE: return state.merge(action.state.get('media_attachments')); default: return state; diff --git a/app/javascript/mastodon/store/configureStore.js b/app/javascript/mastodon/store/configureStore.js index 0fe29f031a..1376d4cbaf 100644 --- a/app/javascript/mastodon/store/configureStore.js +++ b/app/javascript/mastodon/store/configureStore.js @@ -1,36 +1,15 @@ import { createStore, applyMiddleware, compose } from 'redux'; import thunk from 'redux-thunk'; -import appReducer, { createReducer } from '../reducers'; -import { hydrateStoreLazy } from '../actions/store'; -import { hydrateAction } from '../containers/mastodon'; +import appReducer from '../reducers'; import loadingBarMiddleware from '../middleware/loading_bar'; import errorsMiddleware from '../middleware/errors'; import soundsMiddleware from '../middleware/sounds'; export default function configureStore() { - const store = createStore(appReducer, compose(applyMiddleware( + return createStore(appReducer, compose(applyMiddleware( thunk, loadingBarMiddleware({ promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'] }), errorsMiddleware(), soundsMiddleware() ), window.devToolsExtension ? window.devToolsExtension() : f => f)); - - store.asyncReducers = { }; - - return store; }; - -export function injectAsyncReducer(store, name, asyncReducer) { - if (!store.asyncReducers[name]) { - // Keep track that we injected this reducer - store.asyncReducers[name] = asyncReducer; - - // Add the current reducer to the store - store.replaceReducer(createReducer(store.asyncReducers)); - - // The state this reducer handles defaults to its initial state (stored inside the reducer) - // But that state may be out of date because of the server-side hydration, so we replay - // the hydration action but only for this reducer (all async reducers must listen for this dynamic action) - store.dispatch(hydrateStoreLazy(name, hydrateAction.state)); - } -} diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 68d3468590..580d8fb4d2 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -22,19 +22,10 @@ = javascript_pack_tag 'common', integrity: true, crossorigin: 'anonymous' = javascript_pack_tag 'features/getting_started', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/compose', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'reducers/compose', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'reducers/media_attachments', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'reducers/search', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/home_timeline', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/notifications', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'reducers/notifications', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/community_timeline', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' - = javascript_pack_tag 'features/public_timeline', integrity: true, crossorigin: 'anonymous', rel: 'preload', as: 'script' = javascript_pack_tag "locale_#{I18n.locale}", integrity: true, crossorigin: 'anonymous'