How to use react-router-redux routeActions?
Asked Answered
R

5

7

I'm trying to modify the example code of react-router-redux. https://github.com/rackt/react-router-redux/blob/master/examples/basic/components/Home.js

this is my Home.js

class Home extends Component {
    onSubmit(props) {
        this.props.routeActions.push('/foo');    
    }
}

I also have a mapDispatchToProps for it.

function mapDispatchToProps(dispatch){
    return bindActionCreators({ routeActions },dispatch);
}

When i called onSubmit function, I got an error

Uncaught TypeError: this.props.routeActions.push is not a function

If i remove this.props in onSubmit, the key in the URL changed but its still on the same page. From localhost:8080/#/?_k=iwio19 to localhost:8080/#/?_k=ldn1ew

Anyone know how to fix it? Appreciate it.

Ripuarian answered 4/2, 2016 at 9:14 Comment(1)
Show us your complete Home.js please.Govern
M
9

I don't think routeActions are passed as props. What you want to do is this:

import { routeActions } from 'react-router-redux'

this.props.dispatch(routeActions.push('/foo'));
Margartmargate answered 4/2, 2016 at 14:37 Comment(2)
This is indeed how you should do it. The problem comes up when you mapDispatchToProps and still want to use dispatch. for example connect(null, { someAction })(YourComponent) will remove dispatch from props. Any idea how to use routeActions in this scenario?Sentimentalize
I'm sorry I didn't catch that the first time. What if you moved your route action to your actions file and called the route function from there. That way it wouldn't interfere with mapDispatchToProps and you could reuse the action in multiple componentsMargartmargate
S
9

To provide a little more explicit answer and the answer to my own question in the comment.

Yes you can do

import { routeActions } from 'react-router-redux'

this.props.dispatch(routeActions.push('/foo));

However as I mentioned mapDispatchToProps will override this. To fix this you can bind the routeActions like so:

import { bindActionCreators } from 'redux'
import { routeActions } from 'react-router-redux'

function mapDispatchToProps(dispatch) {
    return {
        routeActions: bindActionCreators(routeActions, dispatch),
    }
}

export default connect(null, mapDispatchToProps)(YourComponent)

Now you can do: this.props.routeActions.push('/foo')

Just FYI this can be done even neater

function mapDispatchToProps(dispatch) {
    return {
        ...bindActions({routeActions, anotherAction}, dispatch)
    }
}
Sentimentalize answered 5/2, 2016 at 15:37 Comment(2)
I think routeActions is no longer part of react router redux. Can you please confirm ?Unintentional
It says, Cannot read property 'push' of undefined(…) ,where as import {push} is working fineUnintentional
S
7

As for react-router-redux v4:

import { push } from 'react-router-redux';

export class ExampleContainer extends React.Component {
  static propTypes = {
    changeRoute: React.PropTypes.func,
  };

  function mapDispatchToProps(dispatch) {
    return {
      changeRoute: (url) => dispatch(push(url)),
      dispatch,
    };
  }
}

export default connect(null, mapDispatchToProps)(ExampleContainer);

then:

this.props.changeRoute('/foo');
Samarasamarang answered 9/9, 2016 at 9:14 Comment(1)
Please @Mikhail how do I navigate programmatically if I am using browserHistory in my Router component? I just tried your solution but it didn't work as expected.Yemen
I
5

I was able to get it working by doing this

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { routeActions } from 'react-router-redux'

export const Cmpt = React.createClass({ //code })

function mapDispatchToProps(dispatch) {
  return bindActionCreators({
    push: routeActions.push,
    //all your other action creators here
  }, dispatch)
}

export const CmptContainer = connect({}, mapDispatchToProps)(Cmpt)

Then you can use push via props this.props.push('some/cool/route')

Ionopause answered 6/2, 2016 at 15:51 Comment(1)
this also addresses @Sentimentalize questionIonopause
V
1

More Concisely

For these examples, I'd curry the mapDispatchToProps function like so:

bindActionDispatchers.js

import { bindActionCreators } from 'redux'

/** curries mapDispatchToProps with bindActionCreators to simplify React action dispatchers. */
export default function bindActionDispatchers(actionCreators) {
  if(typeof actionCreators === 'function')
    return (dispatch, ownProps) => bindActionCreators(actionCreators(ownProps), dispatch)
  return dispatch => bindActionCreators(actionCreators, dispatch)
}

Foo.js

import React from 'react'
import bindActionDispatchers from './bindActionDispatchers'
import { routeActions } from 'react-router-redux'
import * as appActions from './actions'

const Foo = ({ routeActions ...appActions }) => (
  <div>
    <button onClick={routeActions.push('/route')}>Route</button>
    <button onClick={appActions.hello('world')}>Hello</button>
  </div>
)

export default connect(null, bindActionDispatchers({ routeActions, ...appActions }))(Foo)

I packaged this into a lightweight npm package bind-action-dispatchers complete with unit tests and sanity checks. To use this version install with:

npm i -S bind-action-dispatchers

and import the function with:

import bindActionDispatchers from 'bind-action-dispatchers'

Venous answered 28/5, 2016 at 3:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.