Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

integrate redux-react-router #41

Closed
athibaud opened this issue Jul 21, 2015 · 17 comments
Closed

integrate redux-react-router #41

athibaud opened this issue Jul 21, 2015 · 17 comments

Comments

@athibaud
Copy link

i tried so myself but to no avail.

has to be a context problem because i get Warning: Failed Context Types: Required context 'store' was not specified in 'Connector'. Check the render method of 'Connector(AppContainer)'.

@erikras
Copy link
Owner

erikras commented Jul 21, 2015

I am watching that project closely, but I'm waiting for it to gain a tad more stability. This will happen eventually, and I welcome any other attempts by @athibaud or others.

@everblaze
Copy link

Using our own actions/reducers we can hang on to the history functions in react router to achieve the desired result, and it will also work when hydrating initial location from the server.. This is the section inside the universalRouter that does majority of the work.

export default function universalRouter(location, history, store) {
  const routes = createRoutes(store);

  store.dispatch(locationDidChange(location));

  if(history && history.addChangeListener){
    store.subscribe(function(){
      let location = store.getState().router.location;
      let {pathname, query, state, navigationType } = location;
      //Only alter if change came from redux state change
      if(history.location != location){
        history.location = new Location(pathname, query, state, navigationType);
        history._notifyChange();
      }
    });
    history.addChangeListener(function(){
      let location = store.getState().router.location;
      let hk = history.location.state && history.location.state.key || null;
      let nk = location.state && location.state.key || null;
      //Only trigger change if history state key is different, location state key is unique
      if(nk != hk){
        store.dispatch(locationDidChange(history.location));
      }
    });
  }

  return new Promise((resolve, reject) => {
    Router.run(routes, location, [createTransitionHook(store)], (error, initialState, transition) => {
      if (error) {
        return reject(error);
      }

      if (transition && transition.redirectInfo) {
        return resolve({
          transition,
          isRedirect: true
        });
      }

      if (history) {  // only on client side
        initialState.history = history;
      }

      const component = (
        <Provider store={store} key="provider"> 
          {() => <Router {...initialState} children={routes}/>}
        </Provider>
      );

      return resolve({
        component,
        isRedirect: false
      });
    });
  });
}

The Router Reducer

import {
  LOCATION_LOAD
} from '../actions/actionTypes';


export default function routerStateReducer(state={}, action = {}) {
    switch (action.type) {
    case LOCATION_LOAD:
      return {
        ...state,
        location: action.router
      };

    default:
      return state;
  }
}

The Action

import {
  LOCATION_LOAD
} from './actionTypes';

export function locationDidChange(location) {
  return {
    type:LOCATION_LOAD,
    router:location
  };
}

This will track all router changes and then allow rollback without tracking as new locations in the redux dev tools. Also does not create history in the browser when rolling back in time with redux.

@quirinpa
Copy link

Hey guys i seem to have integrated redux-react-router in my project which is a clone of this :P it has some problems as stated on redux-react-router's docs like complaining about owner-based and parent-based contexts being different and some other stuff but otherwise works fine

@erikras
Copy link
Owner

erikras commented Aug 18, 2015

@quirinpa and it doesn't suffer from issue #14?

@quirinpa
Copy link

@erikras I don't think so. Here's what i did to investigate:

@connect(state => ({router: state.router}))
export default class Home {
    render() {
        console.log(this.props.router);

and it shows the proper query params in the console when the server renders the DefaultRoute

@erikras
Copy link
Owner

erikras commented Aug 18, 2015

Interesting. I was using 0.2.1, and now it's at 0.4.0. I wonder if that's fixed. I'll check on this again.

Thanks for the update.

@quirinpa
Copy link

np :)

@erikras
Copy link
Owner

erikras commented Aug 20, 2015

@quirinpa No, the problem is that the query parameters aren't present when it's time to fetchData(), at render() is too late.

I just tried with 0.4.0 and it still has the same problem.

@quirinpa
Copy link

@erikras oh i see.. Shame. Also i've experimented with code splitting. I'm not sure to what extent but the page works, as long as you hot reload at least once. Yes... If you don't webpack throws an error "cannot read property call of undefined" because webpack tries to call a module that is not yet defined, i've tried at least 2 require polyfills (hacky stuff) and still no luck. Im missing something in regards to that aswell. Also i've read gaeron say somewhere that actions wouldn't be atributed to the component at start. Sorry if i kept your hopes up. :(

@quirinpa
Copy link

@erikras but more on the topic of redux-react-router i just did:

export default function universalRouter(location, history, store) {
    if (__SERVER__)
        store.dispatch({type: '@@reduxReactRouter/locationDidChange', payload: location });

and it seems to fix that problem, i think

@erikras
Copy link
Owner

erikras commented Aug 20, 2015

This task deserves revisiting after React 0.14 comes out. If it has come out already and you are reading this, leave a comment.

@wmertens
Copy link

I was thinking about this and I might be completely off-base, but:

One possibility to solve this for React 0.13 is to send an action with the router at the start of the app, and then the redux-router middleware should catch and use that instead of relying on context.

Also I am wondering what the best way would be to turn URL state into app state, for example if you have the url "mails/5", it would be nice if you have an appstate reducer that converts that into currentComponent "MailBox" and currentMail 5 instead of relying on the MailBox component to read the params and convert the URL itself. Not sure.

@quirinpa
Copy link

session sync
I've forked redux-react-router, now instead of routerStateReducer, i got something called routerStateReducerCreator to which i can pass location and initialize state and get routerStateReducer. It works. I changed my ways @erikras :)

@acgourley
Copy link
Contributor

@brennanerbz
Copy link

Is there an update using 0.14?

@justingreenberg
Copy link
Contributor

related discussions on rackt/redux/pull/714 and reduxjs/redux#805

@asaf
Copy link

asaf commented Oct 9, 2015

@erikras Close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants