From bc2baaf3b5b3abde9e0e7782ae4b9b9eb3e4265f Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Tue, 7 Feb 2017 13:13:08 +0200 Subject: [PATCH] Refactoring to improve readability, compatibility with saga and comments --- server/fakeSDK.js | 11 ++--------- server/index.js | 8 ++++---- src/containers/SearchPage/SearchPage.ducks.js | 13 +++++-------- src/containers/SearchPage/SearchPage.js | 6 +++--- src/index.js | 3 +++ src/routesConfiguration.js | 16 +++++++++------- src/store.js | 2 +- src/util/fakeSDK.js | 12 +++--------- 8 files changed, 30 insertions(+), 41 deletions(-) diff --git a/server/fakeSDK.js b/server/fakeSDK.js index b06c6371..86effa36 100644 --- a/server/fakeSDK.js +++ b/server/fakeSDK.js @@ -29,14 +29,7 @@ exports.fetchListings = () => { const randomTime = Math.random() * 2000; const fakeResponseTime = 1000 + randomTime; - const fakeFetch = new Promise((resolve, reject) => { - setTimeout( - () => { - resolve({ response: fakeListings }); - // or reject({ error: new Error('FetchListings errored') ); - }, - fakeResponseTime, - ); + return new Promise((resolve, reject) => { + setTimeout(() => resolve(fakeListings), fakeResponseTime); }); - return fakeFetch; }; diff --git a/server/index.js b/server/index.js index abc391bb..9670ce53 100644 --- a/server/index.js +++ b/server/index.js @@ -80,8 +80,8 @@ function fetchInitialState(requestUrl) { // We filter all the components form matched routes that have `loadData` const initialFetches = _ .chain(matchedRoutes) - .filter(r => r.loadData && r.loadData.fetchData) - .map(r => sagaEffects.fork(r.loadData.fetchData, sdk)) + .filter(r => r.loadData) + .map(r => sagaEffects.fork(r.loadData, sdk)) .value(); // We need to combine different onload sagas under one yield @@ -100,8 +100,8 @@ function fetchInitialState(requestUrl) { .catch(e => { reject(e); }); - // Close temporary store (which was used only for fetching initial store state) - store.close(); + // Close temporary store's saga middleware (which was used only for fetching initial store state) + store.closeSagaMiddleware(); }); return fetchPromise; } diff --git a/src/containers/SearchPage/SearchPage.ducks.js b/src/containers/SearchPage/SearchPage.ducks.js index 810f90f7..68626377 100644 --- a/src/containers/SearchPage/SearchPage.ducks.js +++ b/src/containers/SearchPage/SearchPage.ducks.js @@ -4,7 +4,7 @@ * https://github.com/erikras/ducks-modular-redux */ import { unionWith, isEqual } from 'lodash'; -import { call, take, put } from 'redux-saga/effects'; +import { call, put, takeEvery } from 'redux-saga/effects'; import { createRequestTypes } from '../../util/sagaHelpers'; // ================ Action types ================ // @@ -65,10 +65,10 @@ export const loadListings = { // ================ Worker sagas ================ // export function* callFetchListings(sdk) { - const { response, error } = yield call(sdk.fetchListings); - if (response) { + try { + const response = yield call(sdk.fetchListings); yield put(loadListings.success(response)); - } else { + } catch(error) { yield put(loadListings.failure(error)); } } @@ -77,8 +77,5 @@ export function* callFetchListings(sdk) { export function* watchLoadListings(sdk) { // eslint-disable-next-line no-constant-condition - while (true) { - yield take(LOAD_LISTINGS.REQUEST); - yield call(callFetchListings, sdk); - } + yield takeEvery(LOAD_LISTINGS.REQUEST, callFetchListings, sdk); } diff --git a/src/containers/SearchPage/SearchPage.js b/src/containers/SearchPage/SearchPage.js index 7dffcfec..1b48c7fd 100644 --- a/src/containers/SearchPage/SearchPage.js +++ b/src/containers/SearchPage/SearchPage.js @@ -34,10 +34,10 @@ export class SearchPageComponent extends Component { const filtersClassName = classNames(css.filters, { [css.open]: selectedTab === 'filters', }); - const listingsClassName = classNames(css.filters, { + const listingsClassName = classNames(css.listings, { [css.open]: selectedTab === 'listings', }); - const mapClassName = classNames(css.filters, { + const mapClassName = classNames(css.map, { [css.open]: selectedTab === 'map', }); @@ -63,7 +63,7 @@ export class SearchPageComponent extends Component { } } -SearchPageComponent.loadData = { fetchData: callFetchListings, fetchDataAction: loadListings }; +SearchPageComponent.loadData = callFetchListings; SearchPageComponent.defaultProps = { SearchPage: {}, tab: 'listings' }; diff --git a/src/index.js b/src/index.js index 5e9f4bf5..8f61618f 100644 --- a/src/index.js +++ b/src/index.js @@ -33,4 +33,7 @@ if (typeof window !== 'undefined') { // Export the function for server side rendering. export default renderApp; +// exporting matchPathname and configureStore for server side rendering. +// matchPathname helps to figure out which route is called and if it has preloading needs +// configureStore is used for creating initial store state for Redux after preloading export { matchPathname, configureStore }; diff --git a/src/routesConfiguration.js b/src/routesConfiguration.js index 39c26f44..09df1016 100644 --- a/src/routesConfiguration.js +++ b/src/routesConfiguration.js @@ -281,27 +281,29 @@ const pathByRouteName = (nameToFind, routes, params = {}) => * matchRoutesToLocation helps to figure out which routes are related to given location. */ const matchRoutesToLocation = (routes, location, matchedRoutes = [], params = {}) => { - const parameters = { ...params }; + let parameters = { ...params }; + let matched = [...matchedRoutes]; + routes.forEach(route => { const { exactly = false } = route; const match = !route.pattern ? true : matchPattern(route.pattern, location, exactly); if (match) { - matchedRoutes.push(route); + matched.push(route); if (match.params) { - Object.keys(match.params).forEach(key => { - parameters[key] = match.params[key]; - }); + parameters = { ...parameters, ...match.params }; } } if (route.routes) { - matchRoutesToLocation(route.routes, location, matchedRoutes, parameters); + const { matchedRoutes: subRouteMatches, params: subRouteParams } = matchRoutesToLocation(route.routes, location, matched, parameters); + matched = matched.concat(subRouteMatches); + parameters = { ...parameters, ...subRouteParams }; } }); - return { matchedRoutes, params: parameters }; + return { matchedRoutes: matched, params: parameters }; }; const matchPathnameCreator = routes => diff --git a/src/store.js b/src/store.js index 405d6139..a431d492 100644 --- a/src/store.js +++ b/src/store.js @@ -23,7 +23,7 @@ export default function configureStore(initialState = {}) { const store = createStore(createReducer(), initialState, enhancer); store.runSaga = sagaMiddleware.run; - store.close = () => store.dispatch(END); + store.closeSagaMiddleware = () => store.dispatch(END); return store; } diff --git a/src/util/fakeSDK.js b/src/util/fakeSDK.js index 5affbb92..c298a311 100644 --- a/src/util/fakeSDK.js +++ b/src/util/fakeSDK.js @@ -30,16 +30,10 @@ const fakeSDK = { const randomTime = Math.random() * 2000; const fakeResponseTime = 1000 + randomTime; - const fakeFetch = new Promise((resolve, reject) => { - setTimeout( - () => { - resolve({ response: fakeListings }); - // or reject({ error: new Error('FetchListings errored') ); - }, - fakeResponseTime, - ); + return new Promise((resolve, reject) => { + setTimeout(() => resolve(fakeListings), fakeResponseTime); }); - return fakeFetch; }, }; + export default fakeSDK;