aprilmintacpineda
aprilmintacpineda

Reputation: 1274

fetching data before changing route with react-router

I'm using react, react-router, and redux with laravel on the backend and I'm using all the latest releases and I'm actually quite new to these, I just decided I should take my development experiences to the next level and decided to use these based on how I liked them, A LOT.

I have the following problem: When I am in the about-us route, I then click Home but before router renders the home page, it needs to make an async call to the server. I notice that I theoretically need this to be async because it needs to finish before proceeding to the next route.

Then, I want to have a bar on the top of the page that indicates that I am fetching dependencies on the server. Once it is done, it should proceed to the home route.

A practical example is GitHub, example you are on the code tab, then you clicked on the issues tab, a blue loading bar will appear on the very top of the page that indicates that data or dependencies are being fetched then once it's done it will render the next route. How do I do this?

I'm thinking I should use some kind of a middleware, so before the route change I should dispatch an action that will fetch the dependencies that I need then once it's done I should dispatch an action that will update some parts of the redux store, I can't find a way to appy a middleware to react-router though and I really don't know where and how to start.

Upvotes: 1

Views: 7803

Answers (3)

Charles Bensimon
Charles Bensimon

Reputation: 31

Here is an example without redux :

MyPage.jsx

import React from 'react'
import { fetchDataForMyPage } from './someApi'

let data = {}

export default class MyPage extends React.Component {
    constructor() {
        super()
        this.state = {
            /* ... */
            data: data
            /* ... */
        }
    }
    render() {
        /* ... */
    }
    static loadData(routerParams, callback) {
        fetchDataForMyPage(routerParams).then((fetchedData) => {
            data = fetchedData
            callback()
        })
    }
    componentWillReceiveProps() {
        this.setState({
            data: data
        })
    }
}

Routes.jsx

import React from 'react'
import { Route } from 'react-router'
import App from './components/App'
import MyPage from './components/MyPage'

const loadDataOnEnter = (nextState, replace, callback) => {
    const nRoutes = nextState.routes.length
    const component = nextState.routes[nRoutes-1].component
    const params = nextState.params
    component.loadData(params, () => callback())
}

module.exports =
    <Route path="/" component={App}>
        <Route path="mypage/:param1" component={MyPage} onEnter={loadDataOnEnter} />,
        <Route path="anotherpage" component={AnotherPage} onEnter={loadDataOnEnter} />,
        <Route path="somepath" component={SomePageWithoutDataPreloading} />
    </Route>

Upvotes: 3

Shahab Laghaei
Shahab Laghaei

Reputation: 14

if you're using plain redux and router you can use router's lifecycle functions like onEnter (which is calling before entering the view) or onLeave..., then you can do whatever you like and these are accept an callback function when you call it, actual routing happens.

another option is using some redux promise middleware for async jobs such as redux-promise-middleware or simply thunk with loadingbar (as we use them in production) which is works perfectly with async actions.

Redux Promise Middleware

React Redux Loading Bar

Upvotes: -1

Komolafe Tolulope
Komolafe Tolulope

Reputation: 591

This is better handled in the HomePagecomponent where the server call is made. You need to set a state that indicates the call is being processed e.g this.state.loading or this.state.processing and then you can show/hide a loader or the bar based on the value of these. E.g

export default class Home extends React.Component {
 constructor(props) {
  super(props)
   this.state = {processing: false}
 }
 getData(){ //method that makes the server call
  ...//make the call to the server
  this.setState({processing: true})
  //check that the server call returns something and transition to next page when data is returned
 }

 render() {
  return (
   <div>
    {this.state.processing ? "return the loader image" : "else maybe return null"}
    <div>content of the home page</div>
   </div>
  )
 }
}

Upvotes: 0

Related Questions