Skip to content

Instantly share code, notes, and snippets.

@artisin
Created April 10, 2018 00:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save artisin/d56750d955ff4a60ed11e6a714cbd1bd to your computer and use it in GitHub Desktop.
Save artisin/d56750d955ff4a60ed11e6a714cbd1bd to your computer and use it in GitHub Desktop.
react-redux-firebase issues #230
/**
* 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