Created
April 10, 2018 00:12
-
-
Save fetchTe/d56750d955ff4a60ed11e6a714cbd1bd to your computer and use it in GitHub Desktop.
react-redux-firebase issues #230
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* So here's the redux wrapper I used to solve the problem, or at least, that is | |
* what I think. I'm, not all to sure but maybe this will give you some insight. | |
*/ | |
import React, { Component } from 'react'; | |
import thunkMiddleware from 'redux-thunk'; | |
import { Provider } from 'react-redux'; | |
import { createLogger } from 'redux-logger'; | |
import firebase from 'firebase'; | |
import { | |
applyMiddleware, | |
compose, | |
createStore, | |
} from 'redux'; | |
import { | |
getFirebase, | |
reactReduxFirebase, | |
} from 'react-redux-firebase'; | |
import { | |
middleware as memoizationMiddleware | |
} from './redux-memoization'; | |
import reducer from 'reducers/'; | |
// import firebaseConfig from 'constants/firebase.config'; | |
const firebaseConfig = { | |
apiKey: process.env.API_KEY, | |
authDomain: process.env.AUTH_DOMAIN, | |
databaseURL: process.env.DATABASE_URL, | |
storageBucket: process.env.STORAGE_BUCKET, | |
}; | |
/** | |
* Base Firebase App conifg consumed by redux-wrapper | |
*/ | |
const firebaseApp = () => { | |
// check if firebase instance exsits | |
return !firebase.apps.length ? firebase.initializeApp(firebaseConfig) : firebase.app(); | |
}; | |
/** | |
* helper to create redux store for Next.js isomorphic apps | |
* @param {---} options.initStoreReducer → init reducers | |
* @param {---} options.initialState → init state | |
* @param {---} options.req → server req | |
* @return {---} → init store | |
*/ | |
const initStore = ({initStoreReducer, initialState, req}) => { | |
//readux middleware | |
const middlewares = [ | |
//memeomizer → @note not important to the problem | |
memoizationMiddleware, | |
//Pass getFirebase function as extra argument | |
//to get the most out of thunks | |
thunkMiddleware.withExtraArgument(getFirebase), | |
]; | |
if (process.env.NODE_ENV !== 'production') { | |
middlewares.push(...[ | |
//simple logger | |
createLogger({ | |
collapsed: true | |
}), | |
]); | |
} | |
// react-redux-firebase config | |
const reactReduxFirebasefConfig = { | |
userProfile: 'users', | |
// enableLogging: true, | |
enableLogging: false, | |
enableRedirectHandling: false, | |
updateProfileOnLogin: true, | |
setProfilePopulateResults: true, | |
// profileParamsToPopulate: [{ child: 'role', root: 'roles' }], | |
// profileParamsToPopulate: [ | |
// 'reservations', | |
// 'email', | |
// 'reservations:users', | |
// 'contacts:users', | |
// ], | |
}; | |
//shared store args | |
const initStoreArgs = [initStoreReducer, initialState]; | |
const composeArgs = [ | |
reactReduxFirebase(firebaseApp(), reactReduxFirebasefConfig), | |
applyMiddleware(...middlewares), | |
]; | |
// Always make a new store if server | |
if (!process.browser) { | |
req = req || {}; | |
req._store = createStore( | |
...initStoreArgs, | |
compose(...composeArgs), | |
); | |
return req._store; | |
} | |
// Memoize store if client | |
if (!window.store) { | |
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; | |
window.store = createStore( | |
...initStoreArgs, | |
composeEnhancers(...composeArgs), | |
); | |
} | |
return window.store; | |
}; | |
/** | |
* higher order component (HOC) to set up the redux store for components | |
* to share here: https://github.com/zeit/next.js/issues/424 | |
*/ | |
export default (WrappedComponent) => { | |
return class EnhancedComponent extends Component { | |
static displayName = `withRedux(${WrappedComponent.displayName || WrappedComponent.name}`; | |
static async getInitialProps(context) { | |
const { req } = context; | |
const isServer = !!req && typeof window === 'undefined'; | |
const store = initStore({ | |
initStoreReducer: reducer, | |
initialState: undefined, | |
req: req, | |
}); | |
//client set cookies | |
let cookies = req && req.headers && req.headers.cookie || {}; | |
if (typeof cookies === 'string') { | |
const cookie = require('cookie'); | |
cookies = cookie.parse(cookies); | |
} | |
//pass init props to getInitProps wrapped component for ssr ops | |
let wrappedInitialProps = {}; | |
if (WrappedComponent.getInitialProps) { | |
context = { | |
...context, | |
dispatch: store.dispatch, | |
getState: store.getState, | |
initialState: store.initialState, | |
initStoreReducer: reducer, | |
isServer: store.isServer, | |
}; | |
wrappedInitialProps = await WrappedComponent.getInitialProps(context); | |
} | |
//Check for localStorge store cache and pass to cache populate | |
const localStorageStore = process.browser && localStorage && localStorage.store | |
? JSON.parse(localStorage.store) | |
: {}; | |
//→ | |
return { | |
...wrappedInitialProps, | |
cookies, | |
initialState: store.getState(), | |
isServer, | |
localStorageStore, | |
}; | |
} | |
constructor(props) { | |
super(props); | |
this.store = initStore({ | |
initStoreReducer: reducer, | |
initialState: props.initialState, | |
req: null, | |
}); | |
} | |
render() { | |
return ( | |
<Provider store={this.store}> | |
<WrappedComponent {...this.props} /> | |
</Provider> | |
); | |
} | |
}; | |
}; | |
/******************************************************************************* | |
******************************************************************************* | |
******************************************************************************* | |
* Here's an example use with a /page dir root component | |
*/ | |
import React, {Component} from 'react'; | |
import log from 'loglevel'; | |
import { | |
compose, | |
withProps, | |
} from 'recompose'; | |
import Layout from 'components/Layout/Layout'; | |
import enhancedPage from 'containers/enhancedPage'; | |
import Bookings from 'components/Bookings/Bookings'; | |
//@THE IMPORTANT HOC MAGIC THAT HOPEFULLY FIXES YOUR PROBLEMS | |
import withRedux from 'lib/redux-wrapper'; | |
class BookingsPage extends Component { | |
render() { | |
log.info('pages/bookings.js:::RENDER'); | |
return( | |
<Layout {...this.props}> | |
<Bookings /> | |
</Layout> | |
); | |
} | |
} | |
export default compose( | |
withRedux, | |
withProps({ | |
title: 'Bookings', | |
}), | |
enhancedPage, | |
)(BookingsPage); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment