Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react-router : share state between Routes without Redux

I would like to have a shared state (list of clients fetched remotely) between 2 sibling Routes : Timesheets and Clients.
I want to try how far i can go with 'pure' React (No Flux architecture).

This example works, but I have an error : browser.js:49 Warning: [react-router] You cannot change <Router routes>; it will be ignored So, it doesn't seem to like async props.

constructor(props) {
   super(props);
   this.state = {
      clients : []
   }
}

componentDidMount() {
   fetch("clients.json")
     .then(response => response.json()) 
     .then(clients => this.setState({ clients }));
}

render() {
  return (
    <Router history={browserHistory}>
      <Route path="/" component={Header} >
        <Route path="timesheet" component={() => (<Timesheets {...this.state} />) }/>
        <Route path="clients" component={() => (<Clients {...this.state} />) }/>
      </Route>
    </Router>
  );
}

Is it possible to send async props down to each route?
Or is it possible to set the whole state in the parent route (Header component) and then access this state from each child route (Timesheets and Clients components)?

like image 960
gr3g Avatar asked Dec 12 '16 20:12

gr3g


1 Answers

You can use an high-order component to fetch and inject data to your top level component. Then you can pass props to sub routes via React.cloneElement.

HOC

const FetchHOC = url => Component => class extends React.Component() {
   state = { data: null };
   componentDidMount() { 
      fetch(url).then(data => this.setState({ data })); 
   }
   render() {
      return <Component {...this.props} {...this.state.data} />;
   }
}

Route configuration

<Route path="/" component={FetchHOC('http://some-url')(App)}>
   <Route path="subroute1" component={SubRoute1} />
   <Route path="subroute2" component={SubRoute2} />
</Route>

Parent route render()

<div className="App">
   {this.props.children && React.cloneElement(this.props.children, {
      data: this.props.data,
      // ...
   })}
</div>
like image 111
Freez Avatar answered Nov 15 '22 10:11

Freez