React pass dynamic state to all routes in router

832 views Asked by At

I'm trying to pass a dynamic state to all the routes in a React router, specifically a shopping cart (an array of objects).

The layout is I have a parent component which contains the router and all the routes, and in that I want to store the cart in state and pass it to the routes (so essentially all routes will have access to it). I've been trying a few different things and troubleshooting it by looking it up on forums for a while but I just can't get it. This is the latest setup I have:

- Main.jsx

// This is the app entry point
import React, { Component } from 'react';
import { render } from 'react-dom';
import RouterHub from './RouterHub.jsx';

render((
  <RouterHub />
), document.getElementById('root'));

- RouterHub.jsx

import React, { Component } from 'react';
import { render } from 'react-dom';
import { Router, Route, hashHistory } from 'react-router'
import Home from './Home.jsx';
import Dogs from './Pages/Other.jsx';

class RouterHub extends Component {

    constructor(props) {
        super(props);
        this.addItem = this.addItem.bind(this);
        this.state = {
            cart: []
        };
    }

    addItem(item) {
        let newCart = this.state.cart.splice();
        newCart.push(item);
        this.setState({cart: newCart});
    }

    render() {
        return(
            <Router history={hashHistory}>
              <Route path="/" component={Home} cart={this.state.cart} addItem={this.addItem} />
              <Route path="/other" component={Other} cart={this.state.cart} addItem={this.addItem}/>
            </Router>
        );
    }
}

export default RouterHub;

- Home.jsx

import React, { Component } from 'react';
import Slideshow from './Home/Slideshow.jsx';
import Navbar from './Constants/Navbar.jsx';
import Footer from './Constants/Footer.jsx';

class Home extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return(
            <div>
                <button onClick={() => this.props.route.addItem('potato')}>click me</button>
                <Navbar />
                // All the JSX content, I've removed to make it succint
                <Footer />
            </div>
        );
    }
}

export default Home;

Essentially what I'm wanting is in Home.jsx, when I click that button, I want another potato added to the cart. However, with this setup I get the error:

bundle.js:46451 Warning: [react-router] You cannot change <Router routes>; it will be ignored

How do I get it so that updating state in the RouterHub passes that to the routes, or is that not possible and I'm doing this all the wrong way?

Thanks for any help

1

There are 1 answers

2
Juni Brosas On BEST ANSWER

Since you already have a main component for holding your state, you should insert that in the top level Route component something like this:

render((
  <Router history={browserHistory}>
    <Route path="/" component={RouterHub}>
      <Route path="home" component={Home}/>
    </Route>
  </Router>
), document.getElementById('root'))

Then in your RouterHub component, pass those clone each children components with props, something like this:

{ 
   React.Children.map( this.props.children, (child) => {
       return React.cloneElement(child, this.props)
   })
}

Bumping into this kind of problems will make you think of using some state management libraries like Redux/Flux.