6

I'm not using Redux-Router (maybe I have to?) but my router is wrapped by Provider and the store is being passed to that.

I'd like to read state and dispatch in the onEnter handler.

kjs3
  • 5,758
  • 8
  • 34
  • 49

2 Answers2

7

I just wrapped my routes in a function that returns them.

This allows you to pass the redux store as an argument

Any onEnter/onExit functions are also defined in there so they have access to that store argument and can dispatch() stuff.

import React from 'react'
import { IndexRoute, Route } from 'react-router'

import App from './components/app'
import FourOhFour from './components/pages/404'
import Home from './components/home'
import LogIn from './components/account/log_in'
import ResetPassword from './components/account/reset_password'
import SignUp from './components/account/sign_up'

export function getRoutes (store) {
  function doSomething (thing) {
    store.dispatch(addToDoActionCreator(thing))
  }

  function authenticate (nextState, replaceState) {
    const { currentUser } = store.getState();

    if ( !currentUser ) {
      replaceState(null, '/log-in');
    }
  }

  return (
    <Route path='/' component={App}>
      <IndexRoute component={Home} onEnter={(nextState, replaceState)=>{doSomething('get coffee')}} />

      <Route path='log-in' component={LogIn} onEnter={authenticate} />
      <Route path='sign-up' component={SignUp} />
      <Route path='reset-password' component={ResetPassword} />

      <Route path="*" component={FourOhFour}/>
    </Route>
  );
}

On the server side (express.js for me) I establish a redux store fairly early with middleware. Something like this.

server.use((req, res, next) => {
  const createStoreWithMiddleware = applyMiddleware(
    thunkMiddleware
  )(createStore);
  res.store = createStoreWithMiddleware(rootReducer);

  next();
}

So now the store is attached to the response object and can be used by other middleware/routes. They can get state (res.store.getState()) and dispatch to update state.

kjs3
  • 5,758
  • 8
  • 34
  • 49
3

Just create your redux store in an seperate file and require it when it's needed.

// store.js

import { createStore } from 'redux'
import todoApp from './reducers'
  
export default createStore(todoApp);

// the file where you define your routes and onEnter

import { render } from 'react-dom';
import { Router, Route } from 'react-router';
import store, { dispatch } from './store.js';

function enterHandler(){
  dispatch(allTheGoodStuff);
}

render(
  <Router>
    <Route onEnter={ enterHandler } ...
)
Burak Can
  • 64
  • 4
  • 1
    i ran into a race-condition attempting this strategy, so ymmv, see: https://github.com/rackt/react-redux/issues/181#issuecomment-164626032 – tony_k Dec 15 '15 at 03:19
  • 1
    Could you give some details about the situation @DanAbramov ? – Burak Can Dec 15 '15 at 10:18
  • 1
    In server-rendered apps, you'll have a separate store per request, not one global store. See http://redux.js.org/docs/recipes/ServerRendering.html. – Dan Abramov Dec 15 '15 at 14:23
  • I had the action dispatched in cycle until max stack error or something. So I did this: setTimeout( () => dispatch(action) , 0) to put it at the end of js event queue. – koddo Oct 16 '16 at 20:26