react-redux-firebase icon indicating copy to clipboard operation
react-redux-firebase copied to clipboard

bug(examples): SSR recipe is using old API (store.firebase is undefined)

Open lesmo opened this issue 5 years ago • 9 comments

What is the current behavior?

Following the SSR recipe, the store.firebase property is undefined and thus it's not possible to follow it:

import { createStore, applyMiddleware, combineReducers } from 'redux';
import { firebaseReducer } from 'react-redux-firebase'
import { firestoreReducer } from 'redux-firestore';
import reduceReducers from 'reduce-reducers';

const reducers = combineReducers({
  firebase: firebaseReducer,
  firestore: firestoreReducer,
  local: reduceReducers([... someReducers])
});

const store = createStore(persistedReducer, initialState);
store.firebase // <- undefined
store.firestore // <- undefined

I'm trying to get this to work under Razzle/Express. I understand that both firebase and firestore won't be defined at this point (after all we're just setting up reducers here), but I've found no pointers as to when or where are these ever defined or how to get react-redux-firebase to define them.

What is the expected behavior? store.firestore and store.firebase to not be undefined, or documentation to be more clear about when or how these are set...

Which versions of dependencies, and which browser and OS are affected by this issue? Did this work in previous versions or setups?

{
  "redux": "^4.0.4",
  "react-redux-firebase": "^3.0.6",
  "redux-firestore": "^0.11.0",
  "reduce-reducers": "^1.0.4",
}

lesmo avatar Dec 30 '19 02:12 lesmo

You can try calling store.getState() method of the store. It will give the current state of firebase and firestore

harish-aka-shivi avatar Dec 30 '19 09:12 harish-aka-shivi

Thanks for the answer, but that’s not what I’m trying to do. I’m trying to “preload” the store’s state prior to rendering it and returning it from the server.

On Monday, Dec 30, 2019 at 3:36 AM, Harish Rana <[email protected] (mailto:[email protected])> wrote:

You can try calling store.getState() method of the store. It will give the current state of firebase and firestore

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub (https://github.com/prescottprue/react-redux-firebase/issues/815?email_source=notifications&email_token=AAQ77ZBAJHWCMJSI5T3WR4TQ3G6LDA5CNFSM4KBGVCXKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHZ5AMI#issuecomment-569626673), or unsubscribe (https://github.com/notifications/unsubscribe-auth/AAQ77ZAY66RR5VU4SIIBBA3Q3G6LDANCNFSM4KBGVCXA).

lesmo avatar Dec 30 '19 10:12 lesmo

I agree, but I think createStore is a synchronous function. So the state should be initialized as soon as we call it. So you should be able to send the state to the client and use it as described the Redux SSR documentation. And regarding how firebase is initialized, It is done by initializeApp function of firebase and it is extended using createFirestoreInstance. Please let me know if I am not understanding your question.

harish-aka-shivi avatar Dec 30 '19 10:12 harish-aka-shivi

Yeah, I believe I haven't explained myself as good. What I want to achieve is preload data into the Redux store during Server Side Rendering.

According to the documentation, this can be achieved by calling the store.firestore.get() method after the store has been created. However, the store.firestore property is undefined after the store is created... so it cannot be done.

For now I've taken a different approach, pre-filling the Redux's firestore property myself before running React's rendering. It works, but some how doesn't feel proper.

lesmo avatar Jan 01 '20 03:01 lesmo

Hmm, I get it. Actually someone just asked the same question on RRF Gitter community. He had used getFirebase to workaround the issue. Please check if there is getFirestore method on the store. In any case, the documentation needs some change to provide clarity on the issue.

Heyo, I'm trying to figure out the SSR stuff with react-redux-firebase. In the docs, it seems to indicate that there should be a firebase instance on the store, but I'm not seeing one. Where does that instance normally get added? I'm currently importing getFirebase from react-redux-firebase to get around it, but I feel like this may be an issue in the future if I don't figure it out. Also, when I use await getFirebase().promiseEvents([...]), it doesn't actually populate anything in the Redux store. There are no errors or anything, though. FWIW, I'm using Next.js.

harish-aka-shivi avatar Jan 01 '20 07:01 harish-aka-shivi

Hmm, I get it. Actually someone just asked the same question on RRF Gitter community.

I think I stumbled upon that question when I was researching this problem.

He had used getFirebase to workaround the issue. Please check if there is getFirestore method on the store. In any case, the documentation needs some change to provide clarity on the issue.

Totally! I'm pretty sure is more of a documentation issue than anything else. I'm no longer trying to get this solution working, but I can tell you that the store object didn't have getFirestore defined after creating it.

Perhaps when I get some freetime I'll try to make a repro and further research the issue.

lesmo avatar Jan 24 '20 04:01 lesmo

React context is used now instead of placing the extended Firebase instance on the store (under store.firebase). In v3 store.firebase and store.firestore being undefined is expected. I agree it is probably an issue of docs not being up to date

prescottprue avatar Jan 24 '20 19:01 prescottprue

React context is hard to use on server as it require to render app twice. So enhancers on store makes everything much simpler and faster.

I wanted to preload data from firestore, and I don't like the idea of populating store by hand. I found that redux-firestore still exports reduxFirestore enhancer, and it works as expected. So here is my solution.

// create store with enhancer
import { createStore, compose } from 'redux';
import { createFirestoreInstance, reduxFirestore } from 'redux-firestore';
import firebase from './firebase';
import rootReducer from './reducers';

export function configureStore() {
  return createStore(
    rootReducer,
    {},
    compose(
      reduxFirestore(firebase)
    )
  );
}
// check out react-router-config README
const routes = [
  {
    path: '/test/path',
    exact: true,
    component: TestContainer,
    // we call loadData on server, and it returns promise
    // so we can wait for it to finish before sending page to client
    loadData(firestore, branch) {
      return firestore.get('collection_name');
    }
  }
];
export default routes;
// on server side
import { StaticRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { ReactReduxFirebaseProvider } from 'react-redux-firebase';
import { matchRoutes } from 'react-router-config';
import { configureStore } from './store';
import routes from './routes';
import App from './App';

const store = configureStore();
const routerContext = {};

const handleUniversalRender = (req, res) => {
  const template = (
    <Provider store={store}>
      <ReactReduxFirebaseProvider {...rrfProps}>
        <StaticRouter
          location={req.url}
          context={routerContext}
        >
          <App />
        </StaticRouter>
      </ReactReduxFirebaseProvider>
    </Provider>
  );
  const branch = matchRoutes(routes, req.url);
  const route = branch && branch[0] && branch[0].route;
  if (route && route.loadData) {
    return route.loadData(store.firestore, branch[0])
      .then(() => template); // store populated, hurray
  }
  return Promise.resolve(template);
}

komachi avatar Aug 06 '20 14:08 komachi

Is there not a simple way to pull stuff out of react context in getInitialProps?

devth avatar Aug 12 '20 15:08 devth