Coder Social home page Coder Social logo

victortrusov / react-router-loading Goto Github PK

View Code? Open in Web Editor NEW
61.0 4.0 13.0 3.83 MB

Wrapper for react-router that allows you to load data before switching the screen

License: MIT License

JavaScript 14.23% TypeScript 85.77%
router topbar switching react fetch loading prefetch preloading react-router bar

react-router-loading's Introduction

react-router-loading · npm version

Wrapper for react-router that allows you to load data before switching the screen


DEMO (React Router 6)
DEMO 0.x.x (React Router 5)

Requirements

‼️ Version 1.x.x supports React Router 6 only, please use version 0.x.x for React Router 5 ‼️

react >= 16.8
react-router ^5.0.0 Package version 0.x.x
react-router ^6.0.0 Package version 1.x.x

This package uses react-router (react-router-dom or react-router-native) as main router so you should implement it in your project first.

Installation

npm install react-router-loading
## or
yarn add react-router-loading

Usage

React Router 6 (package version 1.x.x)

In your router section import Routes and Route from react-router-loading instead of react-router-dom or react-router-native

import { Routes, Route } from "react-router-loading";

<Routes>
    <Route path="/page1" element={<Page1 />} />
    <Route path="/page2" element={<Page2 />} />
    ...
</Routes>

Add loading prop to every route that needs to be loaded before switching

<Routes>
    // data will be loaded before switching
    <Route path="/page1" element={<Page1 />} loading />

    // instant switch as before
    <Route path="/page2" element={<Page2 />} />
    ...
</Routes>

Add loadingContext.done() at the end of your initial loading method in components that mentioned in routes with loading prop (in this case it's Page1)

import { useLoadingContext } from "react-router-loading";
const loadingContext = useLoadingContext();

const loading = async () => {
    // loading some data

    // call method to indicate that loading is done and we are ready to switch
    loadingContext.done();
};

React Router 5 (package version 0.x.x)

In your router section import Switch and Route from react-router-loading instead of react-router-dom

import { Switch, Route } from "react-router-loading";

<Switch>
    <Route path="/page1" component={Page1} />
    <Route path="/page2" component={Page2} />
    ...
</Switch>

Add loading prop to every route that needs to be loaded before switching

<Switch>
    // data will be loaded before switching
    <Route path="/page1" component={Page1} loading />

    // instant switch as before
    <Route path="/page2" component={Page2} />
    ...
</Switch>

Add loadingContext.done() at the end of your initial loading method in components that mentioned in routes with loading prop (in this case it's Page1)

import { LoadingContext } from "react-router-loading";
const loadingContext = useContext(LoadingContext);

const loading = async () => {
    // loading some data

    // call method to indicate that loading is done and we are ready to switch
    loadingContext.done();
};

Class components

import { LoadingContext } from "react-router-loading";

class ClassComponent extends React.Component {
    ...
    loading = async () => {
        // loading some data

        // call method from props to indicate that loading is done
        this.props.loadingContext.done();
    };
    ...
};

// we should wrap class component with Context Provider to get access to loading methods
const ClassComponentWrapper = (props) =>
    <LoadingContext.Consumer>
        {loadingContext => <ClassComponent loadingContext={loadingContext} {...props} />}
    </LoadingContext.Consumer>

Config

You can specify loading screen that will be shown at the first loading of your app

const MyLoadingScreen = () => <div>Loading...</div>

<Routes loadingScreen={MyLoadingScreen}> // or <Switch>
...
</Routes>

Use maxLoadingTime property if you want to limit loading time. Pages will switch if loading takes more time than specified in this property (ms).

<Routes maxLoadingTime={500}> // or <Switch>
...
</Routes>

If you want to change LoadingContext globally you can pass isLoading property to the <Routes /> or <Switch />. This way you don't need to add extra loadingContext.done(); in your page components after fetching is done.

import { useIsFetching } from 'react-query';
const isFetching = useIsFetching();

<Routes isLoading={isFetching}> // or <Switch>
...
</Routes>

Call topbar.config() if you want to change topbar configuration. More info here.

import { topbar } from "react-router-loading";

topbar.config({
    autoRun: false,
    barThickness: 5,
    barColors: {
        0: 'rgba(26,  188, 156, .7)',
        .3: 'rgba(41,  128, 185, .7)',
        1.0: 'rgba(231, 76,  60,  .7)'
    },
    shadowBlur: 5,
    shadowColor: 'red',
    className: 'topbar'
});

Development

Clone repository and run

# go to lib folder
cd packages/react-router-loading

# restore packages
yarn

# build lib
yarn build

# go to example folder
cd ../../examples/react-router-6

# restore packages
yarn

# run example
yarn dev

run yarn build in lib folder each time you want to apply changes

License

MIT

react-router-loading's People

Contributors

basselashi avatar dependabot[bot] avatar jayarjo avatar pavlmais avatar syadykin avatar victortrusov avatar yashmahalwal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

react-router-loading's Issues

Dynamic routes do not work

The Switch doesn't seem to recognize dynamically inserted routes, eg.:

<Switch>
    { routes.map(route => <Route key={route.id} path={route.path} loading>
        { React.createElement(getComponent(route.component) }
    </Route>}
</Switch>

The routes simply do not work. If I manually add routes outside the .map(), they work as expected. The dynamic routes work as expected in react-router-dom.

Any workaround or a way to get this working, or is the support for this use case just missing?

react-router-dom vs react-router issue

First thank you for taking your time and abstracting out loading functionality like this. Now regarding the issue that I observe.

In peerDependencies you specify react-router-dom as a dependency, however in components you tend to use react-router (like here), which is not an equivalent and is in fact conflicting with the former one, 'causing nasty and sometimes unreproducible issues.

I'd suggest to import from react-router-dom everywhere.

There is no way to use LoadingContext globally

I need to change LoadigContext globally, now I'm trying this code

import { useContext, useEffect } from 'react';
import { Route, LoadingContext, Switch, } from "react-router-loading"
import { useIsFetching } from 'react-query'

const App = () => {
  const loadingContext = useContext(LoadingContext);
  const isFetching = useIsFetching()

  useEffect(() => {
    // handle loading state globally by external library
    if(isFetching) loadingContext.start()
    else loadingContext.done()
  }, [isFetching])


  return (
    <Switch>
      <Route loading path="/" component={HomePage} />
      <Route loading path="/user" component={UserPage} />
      <Route loading path="/developer/:id" component={SettingPage} />
    </Switch>
  )
}

So the LoadingContext is not available because provided in Switch component
and I don't know any other ways to get LoadingContext globally

Error: Could not find a declaration file for module

tsc throws the following error:

error TS7016: Could not find a declaration file for module 'react-router-loading'. './node_modules/react-router-loading/dist/react-router-loading.es.js' implicitly has an 'any' type.

There are types at './node_modules/react-router-loading/dist/index.d.ts', but this result could not be resolved when respecting package.json "exports". The 'react-router-loading' library may need to update its package.json or typings.

Wildcard and fallback routes do not work

This lib was a great help to me but I believe I found two bugs. In the below example, the expected behavior is to have the NotFoundPage component render any non matching path. Instead the router renders nothing.

<Switch>
    <Route path="/page1" component={Page1} />
    <Route path="/page2" component={Page2} />
    ...
    <Route component={NotFoundPage} />
</Switch>

Bug 2: When using a wildcard path an error is thrown, "Error: Invariant failed: You should not use <Route> outside a <Router>".

<Switch>
    <Route path="/page1" component={Page1} />
    <Route path="/page2" component={Page2} />
    ...
    <Route path="*" component={NotFoundPage} />
</Switch>

I was able to fix the first bug by modifying findMatchingRoute (https://github.com/victortrusov/react-router-loading/blob/master/src/utils.js#L6) to force a match when there is no path attribute on a route but I'm unsure if that breaks anything else. I suspect a better fix would solve both problems at once.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.