Skip to content

Instantly share code, notes, and snippets.

@fetchTe
Created April 10, 2018 00:12
Show Gist options
  • Save fetchTe/d56750d955ff4a60ed11e6a714cbd1bd to your computer and use it in GitHub Desktop.
Save fetchTe/d56750d955ff4a60ed11e6a714cbd1bd to your computer and use it in GitHub Desktop.

Revisions

  1. fetchTe created this gist Apr 10, 2018.
    230 changes: 230 additions & 0 deletions react-redux-firebase-issues-230.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,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);