klendi / react-top-loading-bar Goto Github PK
View Code? Open in Web Editor NEWA very simple, highly customisable youtube-like react loader component.
Home Page: https://klendi.github.io/react-top-loading-bar/
License: MIT License
A very simple, highly customisable youtube-like react loader component.
Home Page: https://klendi.github.io/react-top-loading-bar/
License: MIT License
Is it possible to use LoadingBar on React Functional Component?
When using the continuous bar you add a random value to the current percentage within each interval call
const random = randomInt(10, 20)
After that you check if the current percentage plus the random value is below 90.
if (localProgress + random < 90) {
If below 90 you set the new progress value, otherwise nothing happens. This means if you have a percentage of 80+ nothing will happen because any random value will be at least 10 and therefor too high.
I would suggest a different approach for the random value
const random = randomInt(Math.min(10, (100-localProgress)/5), Math.min(20, (100-localProgress)/3));
This would keep the random lower value at 10 until 50% and the upper value at 20 until 40%. After the the random values will be chosen between 1/5 and 1/3 of the remaining percentage, meaning you decrease those values constantly as the bar gets wider. Additionally you should change the condition above to lower as 100 instead of 90.
This would slow down the loading bar as it gets closer and closer to 100% but at least if won't get stuck.
Another thing I'd consider would be changing the randomInt function to a random float function in that case. Since CSS is perfectly fine with fraction width values and it would give the bar more possible width values.
When I add:
<LoadingBar
className="loading"
progress={progress}
onLoaderFinished={() => setProgress(0)}
/>
Styles:
.loading {
background: #FFF;
}
The color remains red.
It's not working. How to change loading bar color with className?
Hello there, is there any way to use it with next.js?
The CSS injector violates a secure content security policy. In order for this to work, unsafe-inline must be used on the style-src attribute.
It should be possible to define if we want to import the CSS manually or automatically. In my opinion, you could completely remove the automatic inject of CSS, because this is insecure.
Hello, and thanks for this great piece of UI.
The bug I'm reporting is probably a minor one, because you can always call complete
a second time to be sure, but anyway.
I am using Apollo GraphQL and I am calling continuousStart when any query is triggered and complete when the query stops loading. It seems that, sometimes apollo can change state synchronously. Probably this makes that within the same render the state goes from loading to not loading, without even giving the components a chance to update or render. I think that it is because of this that I am having a problem with this library. I call the continuousStart on query start, and almost immediately complete is called. As a result, the bar completes and then starts again, but this time it never finishes.
I have created a small codesanbox sample, let me know if it is enough to troubleshoot this:
https://codesandbox.io/s/peaceful-leakey-4g0u5?file=/src/index.js
We use the loading bar inside another component and would like to use the types from the package itself to avoid copying. Could you please make the types exportable?
Hi!
<div style={{ height }}> {show ? ( <div className={ styles['loading-bar'] + ' ' + (className || '') + ' ' + (full ? styles['loading-bar-full'] : '') } style={this.barStyle()} /> ) : null} </div>
The progress bar is rendered as 2 nested divs, the external div only serves the pupose of setting bar height. The first div is static and leaves an empty space on the top of the viewport.
Why not drop the external div and pass the height prop ?
After updating version of React to 16.9.0 it shows warning about usage of depricated componentWillReceiveProps
method in the console
backend.js:1 Warning: componentWillReceiveProps has been renamed, and is not recommended for use. See https://fb.me/react-async-component-lifecycle-hooks for details.
* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state
* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.
Please update the following components: LoadingBar
i get this type of warning.
I am using directioni rtl in internationalization. So how could I change the loading bar direction to right to left
I am using React Hooks for a personal project, and wanted to use the in-built LoadingBar.continousStart()
function. I understand how this would work if my Loader component was a stateful component, your example is pretty clear on that:
<LoadingBar
...
onRef={ref => {this.loadingBarRef = ref}}
/>
But in my scenario, I am using hooks, which pretty much eliminates the this
keyword. There is a Hooks API for refs
that I have utilized for my other functional components, but when I do the same thing for LoadingBar
, I get the following error:
Warning: Failed prop type: Invalid prop
onRef
of typeobject
supplied toLoadingBar
, expectedfunction
.
Is there a solution for this?
Thanks for the library btw, it's really nice 😄
Hello,
I used react-top-loading-bar in a simple way in a component library:
<LoadingBar
shadow={false}
progress={missionsDownloadProgress}
height={3}
color='#00AAC2'
/>
So when I link the library to my application, I have a hook problem:
I inspected hook in react-top-loading-bar code and didn't find anything ... but in the file index.modern.js from npmjs package I found this:
and it seems corrrspond to this code:
To summaries:
Object(__WEBPACK_IMPORTED_MODULE_0_react__["useRef"])
=> checkIfFull
I deleted the index.modern.js" frile from the node_module package
react-top-loading-barand webpack used
index.jsfile instead, and seems work perfectly. But I don't know how to configure webpack to use
index.jsinstead of
index.modern.jsand I don't know if
index.modern.js``` is generated correctly.
0 verbose cli [
0 verbose cli 'C:\Program Files\nodejs\node.exe',
0 verbose cli 'C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js',
0 verbose cli 'i',
0 verbose cli 'react-top-loading-bar'
0 verbose cli ]
1 info using [email protected]
2 info using [email protected]
3 timing npm:load:whichnode Completed in 1ms
4 timing config:load:defaults Completed in 2ms
5 timing config:load:file:C:\Program Files\nodejs\node_modules\npm\npmrc Completed in 10ms
6 timing config:load:builtin Completed in 10ms
7 timing config:load:cli Completed in 2ms
8 timing config:load:env Completed in 1ms
9 timing config:load:file:C:\Users\admin\Desktop\mywork\newsapp.npmrc Completed in 0ms
10 timing config:load:project Completed in 3ms
11 timing config:load:file:C:\Users\admin.npmrc Completed in 0ms
12 timing config:load:user Completed in 1ms
13 timing config:load:file:C:\Users\admin\AppData\Roaming\npm\etc\npmrc Completed in 0ms
14 timing config:load:global Completed in 0ms
15 timing config:load:validate Completed in 0ms
16 timing config:load:credentials Completed in 1ms
17 timing config:load:setEnvs Completed in 2ms
18 timing config:load Completed in 24ms
19 timing npm:load:configload Completed in 24ms
20 timing npm:load:setTitle Completed in 0ms
21 timing config:load:flatten Completed in 4ms
22 timing npm:load:display Completed in 6ms
23 verbose logfile C:\Users\admin\AppData\Local\npm-cache_logs\2022-05-20T06_48_25_449Z-debug-0.log
24 timing npm:load:logFile Completed in 64ms
25 timing npm:load:timers Completed in 0ms
26 timing npm:load:configScope Completed in 0ms
27 timing npm:load Completed in 97ms
28 timing arborist:ctor Completed in 2ms
29 silly logfile start cleaning logs, removing 3 files
30 timing idealTree:init Completed in 1778ms
31 timing idealTree:userRequests Completed in 9ms
32 silly idealTree buildDeps
33 silly fetch manifest react-top-loading-bar@*
34 silly logfile error removing log file C:/Users/admin/AppData/Local/npm-cache/_logs/2022-05-20T05_03_57_603Z-debug-0.log [Error: EPERM: operation not permitted, lstat 'C:\Users\admin\AppData\Local\npm-cache_logs\2022-05-20T05_03_57_603Z-debug-0.log'] {
34 silly logfile errno: -4048,
34 silly logfile code: 'EPERM',
34 silly logfile syscall: 'lstat',
34 silly logfile path: 'C:\Users\admin\AppData\Local\npm-cache\_logs\2022-05-20T05_03_57_603Z-debug-0.log'
34 silly logfile }
35 timing arborist:ctor Completed in 0ms
36 http fetch GET 200 https://registry.npmjs.org/react-top-loading-bar 1278ms (cache hit)
37 silly fetch manifest react@^18.1.0
38 http fetch GET 200 https://registry.npmjs.org/react 16ms (cache hit)
39 silly fetch manifest react@^16 || ^17
40 timing idealTree Completed in 3121ms
41 timing command:i Completed in 3143ms
42 verbose stack Error: unable to resolve dependency tree
42 verbose stack at Arborist.[failPeerConflict] (C:\Program Files\nodejs\node_modules\npm\node_modules@npmcli\arborist\lib\arborist\build-ideal-tree.js:1398:25)
42 verbose stack at Arborist.[loadPeerSet] (C:\Program Files\nodejs\node_modules\npm\node_modules@npmcli\arborist\lib\arborist\build-ideal-tree.js:1364:34)
42 verbose stack at async Arborist.[buildDepStep] (C:\Program Files\nodejs\node_modules\npm\node_modules@npmcli\arborist\lib\arborist\build-ideal-tree.js:950:11)
42 verbose stack at async Arborist.buildIdealTree (C:\Program Files\nodejs\node_modules\npm\node_modules@npmcli\arborist\lib\arborist\build-ideal-tree.js:216:7)
42 verbose stack at async Promise.all (index 1)
42 verbose stack at async Arborist.reify (C:\Program Files\nodejs\node_modules\npm\node_modules@npmcli\arborist\lib\arborist\reify.js:153:5)
42 verbose stack at async Install.exec (C:\Program Files\nodejs\node_modules\npm\lib\commands\install.js:159:5)
42 verbose stack at async module.exports (C:\Program Files\nodejs\node_modules\npm\lib\cli.js:66:5)
43 verbose cwd C:\Users\admin\Desktop\mywork\newsapp
44 verbose Windows_NT 10.0.19044
45 verbose argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "i" "react-top-loading-bar"
46 verbose node v16.15.0
47 verbose npm v8.5.5
48 error code ERESOLVE
49 error ERESOLVE unable to resolve dependency tree
50 error
51 error While resolving: �[1mnewsapp�[22m@�[1m0.1.0�[22m
51 error Found: �[1mreact�[22m@�[1m18.1.0�[22m�[2m�[22m
51 error �[2mnode_modules/react�[22m
51 error �[1mreact�[22m@"�[1m^18.1.0�[22m" from the root project
51 error
51 error Could not resolve dependency:
51 error �[35mpeer�[39m �[1mreact�[22m@"�[1m^16 || ^17�[22m" from �[1mreact-top-loading-bar�[22m@�[1m2.1.0�[22m�[2m�[22m
51 error �[2mnode_modules/react-top-loading-bar�[22m
51 error �[1mreact-top-loading-bar�[22m@"�[1m*�[22m" from the root project
51 error
51 error Fix the upstream dependency conflict, or retry
51 error this command with --force, or --legacy-peer-deps
51 error to accept an incorrect (and potentially broken) dependency resolution.
51 error
51 error See C:\Users\admin\AppData\Local\npm-cache\eresolve-report.txt for a full report.
52 verbose exit 1
53 timing npm Completed in 3808ms
54 verbose unfinished npm timer reify 1653029306091
55 verbose unfinished npm timer reify:loadTrees 1653029306106
56 verbose unfinished npm timer idealTree:buildDeps 1653029307896
57 verbose unfinished npm timer idealTree:#root 1653029307897
58 verbose code 1
59 error A complete log of this run can be found in:
59 error C:\Users\admin\AppData\Local\npm-cache_logs\2022-05-20T06_48_25_449Z-debug-0.log
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR! react@"^18.1.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16 || ^17" from [email protected]
npm ERR! node_modules/react-top-loading-bar
npm ERR! react-top-loading-bar@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See C:\Users\admin\AppData\Local\npm-cache\eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\admin\AppData\Local\npm-cache_logs\2022-05-20T06_48_25_449Z-debug-0.log
Is there gonna be a version bump for react 17?
I have reviewed the source code and I think it's pretty compatible with react 17, since you have started function components and hooks from the start.
I will very much appreciate if you announce whether you're going to support it, or should I fork, or whether I can submit a pull request.
Also tests can really help the PR and maintenance process.
Thanks for your awesome component!
Cheers.
hi
can anyone provide me an usage example for nextjs project ? i want to use it on every page of the website. whenever page will be reloading / refreshed then it must show the topbar ? how to do it? which means it must not be controlled by any button rather it will be controlled while the page will be refreshed/reloaded etc.
let me know an easy way to achieve it.
I found this bug:
it is repro when the component unmounted and the setTimeout functions still trying to setState!
and I suggest this fix:
`
import PropTypes from "prop-types";
import React, { Component } from "react";
import "./styles.css";
class LoadingBar extends Component {
state = {
show: true,
full: false,
progress: 0,
wait: false,
};
add = value => {
this.setState({ progress: this.state.progress + value }, () => {
this.onProgressChange();
});
};
onProgressChange = () => {
if (this.props.onProgressChange)
this.props.onProgressChange(this.state.progress);
this.checkIfFull();
};
decrease = value => {
this.setState({ progress: this.state.progress - value }, () => {
this.onProgressChange();
});
};
randomInt(low, high) {
return Math.floor(Math.random() * (high - low) + low);
}
continuosStart = startingValue => {
console.log('loading-bar' )
const random = startingValue || this.randomInt(20, 30);
this.setState({ progress: random });
const interval = setInterval(() => {
if (this.state.progress < 90) {
const random = this.randomInt(2, 10);
if (!this.mounted) return false;
this.setState({ progress: this.state.progress + random }, () => {
this.onProgressChange();
});
} else {
clearInterval(interval);
}
}, 1000);
};
staticStart = startingValue => {
const random = startingValue || this.randomInt(30, 50);
this.setState({ progress: random }, () => {
this.onProgressChange();
});
};
complete = () => {
this.setState({ progress: 100 }, () => {
this.onProgressChange();
});
};
onLoaderFinished = () => {
if (this.props.onLoaderFinished) this.props.onLoaderFinished();
this.setState({ progress: 0 }, () => {
this.onProgressChange();
});
};
render() {
const { className, height } = this.props;
const { show, full } = this.state;
return (
<div style={{ height: height }}>
{show ? (
<div
className={
"loading-bar" +
" " +
(className || "") +
" " +
(full ? "loading-bar-full" : "")
}
style={this.barStyle()}
/>
) : null}
);
}
componentWillReceiveProps(nextProps) {
// Watching Progress Changes
if (nextProps.progress !== this.props.progress) {
this.setState({ progress: nextProps.progress }, () => {
if (this.props.onProgressChange != null) {
this.props.onProgressChange();
}
this.checkIfFull();
});
}
}
componentDidMount() {
if (this.props.onRef) this.props.onRef(this);
this.mounted = true; // fix cancel a fetch on componentWillUnmount
if (this.state.progress !== this.props.progress) {
this.setState({ progress: this.props.progress });
}
}
componentWillUnmount() {
if (this.props.onRef) this.props.onRef(undefined);
this.mounted = false;
}
// Check whether the proggress is full
checkIfFull = () => {
if (!this.mounted) return false;
if (this.state.progress >= 100) {
// Prevent new progress change
this.setState({ wait: true });
// Start animate it
setTimeout(() => {
if (!this.mounted) return false;
// animate when element removed
this.setState({
full: true,
myError: false,
});
setTimeout(() => {
if (!this.mounted) return false;
this.setState({
// remove bar element
show: false,
progress: 0,
wait: false,
});
setTimeout(() => {
if (!this.mounted) return false;
this.setState({
// Show Bar
full: false,
show: true,
});
this.onLoaderFinished();
});
// Duration to Waiting for hiding animation
}, 250);
// Duration is depend on css animation-duration of loading-bar
}, 700);
}
};
// apply width style to our element as inline style
barStyle() {
// When loading bar still in progress
const { color } = this.props;
if (!this.state.wait) {
return {
width: `${this.state.progress}%`,
backgroundColor: color,
};
} else {
return { width: "100%", backgroundColor: color };
}
}
}
LoadingBar.defaultProps = {
progress: 0,
color: "#f11946",
height: 3,
className: "",
};
LoadingBar.propTypes = {
progress: PropTypes.number,
color: PropTypes.string,
height: PropTypes.number,
onLoaderFinished: PropTypes.func,
onProgressChange: PropTypes.func,
className: PropTypes.string,
onRef: PropTypes.func,
};
export default LoadingBar;
`
Hey there, great component! Thanks for the contribution! I'm wondering if it's possible to get gradients or background images on it?
Something like this?
<LoadingBar
progress={ someProgressFunc }
height={3}
// color="red"
backgroundImage="linear-gradient(90deg, rgba(2,0,36,1) 0%, #00AD00 50%, #0077AD 100%)"
onLoaderFinished={() => this.onLoaderFinished()}
/>
thanks
Thanks for this component! I know that you can provide a className and use a stylesheet to style the component, but it would also be nice to just be able to use a style prop. I use CSS-in-JS and don't often add full style sheets. Something like this...
<LoadingBar ref={ref} style={{ width: '50%' }} />
Just a suggestion. Thank you!
Can this library be used as fallback content for React.Suspense ?
You got me, but please add this feature it will go a long way
continousStart should be continuousStart. :)
Since this is a breaking change, maybe you could add the correct one and add a deprecation notice on the one with the incorrect name.
Hi,
there's been some fixes recently that would be nice to have installed. Would it be possible to do a new release on npm?
Thank you for the useful package!
I could not find an easy way to get the types for the Ref, so I am typing it myself. However, it'd be quite nice if this was coming with the library:
type LoadingBarRef = {
add(value: number): void;
decrease(value: number): void;
continuousStart(startingValue?: number, refreshRate?: number): void;
staticStart(startingValue: number): void;
complete(): void;
};
Hey @klendi is there anyway to set a smooth continuous loading?
Like if we want the bar to complete after 5s, what we're doing now is just setting an interval to increase the bar by 1 every 50ms. It's not a super smooth experience though. Anything you suggest?
This seems like a great project; I do have a question, however.
The loading bar seems to always start at the top left of the page, regardless of placement of the LoadingBar inside the application. How to make the loading bar fit inside a card for example?
or in the case of an application using a vertical navigation bar, how could the loading bar start next to the navbar, rather than to always start from the top left of the page (meaning it would start on top of the navbar)?
First of all, thanks for great module!
I am trying to change color using code like
<LoadingBar
height={10}
color='#ff9b20'
onRef={ref => (this.LoadingBar = ref)}
/>
but its still red. In final html code I dont have background-color property in styles, only height
After playing around with sources I founded a bug - looks like you cant use backgroundColor with bacground in style property (even if background is empty)
code like
<h1>Not working color</h1>
<div style={{height:"10px"}}>
<div style={{backgroundColor: "#ff9b20", background: "", width: "40%", height: "10px"}}></div>
</div>
<h1>Working</h1>
<div style={{height:"10px"}}>
<div style={{backgroundColor: "#ff9b20", width: "40%", height: "10px"}}></div>
</div>
I am not sure about your usecases for background prop, so I cant make PR
I have added simple repo, so you can check this bug yourself
https://github.com/zhil/preloader-bug
Function barStyle() need to be fixed
https://github.com/klendi/react-top-loading-bar/blob/master/src/index.tsx#L222
const [loadBar, setLoadBar] = useState();
const onLoaderFinished = num => {
setLoadBar(num);
};
return(
<LoadingBar
progress={loadBar}
height={3}
color={barColor}
onLoaderFinished={() => onLoaderFinished(20)}
/>
)
Hi! This is not an issue but a feature request.
Is it possible to expose the current progress in ref.current.currentProgress
? It could also be a getter function ref.current.getProgress()
.
The use case is a little difficult to explain but I'll do my best:
I'm building a SPA app using react-router
and react-query
. On each page navigation I load some data before transitioning to the new page (using react-router's loader functions) and I cache that data client side using react-query
. If the transition is from Page A to Page B, the loading bar is shown because the data for Page B is still not cached. When I transition back to Page A I don't want to show the loading bar because the data is immediately available in the cache.
The way I'm trying to solve this is with a wrapper that checks the navigation state and shows the loading bar conditionally:
function ConditionalLoadingBar() {
const navigation = useNavigation();
const ref = useRef<LoadingBarRef | null>(null);
useEffect(() => {
if (ref.current) {
// Wait 200 ms before showing the loading bar
if (navigation.state === 'loading') {
const timeoutId = setTimeout(() => {
ref.current.continuousStart();
}, 200);
// Clear the timeout if navigation.state changed.
// This will prevent the loading bar from starting if the change occurred in less than 200ms
return () => clearTimeout(timeoutId);
} else if (ref.current.getProgress() > 0) {
// Complete the loading bar only if it started at some point (a.k.a progress > 0)
ref.current.complete();
}
}
}, [navigation.state]);
return <LoadingBar color="#14CC9E" ref={ref} />;
}
As you can see, the bit I'm missing is getting the current progress value to make the check before completing. Without this, the loading bar flashes when the data is cached which is kind of distracting for the user.
Also, with this approach we get the benefit to show the loading bar only for transitions that take more than a desired threshold. This behavior could even be provided by the LoadingBar
component with a prop that specifies the threshold or delay before starting the progress transitions.
Repro: https://codesandbox.io/s/react-top-loading-bar-typing-kxsdn
It seems that the continuousStart
typings have recently been updated. The method now requires two mandatory paramters "startingValue" and "refreshRate".
The method's type is currently:
((startingValue: number, refreshRate: number) => void) | undefined
Shouldn't it be:
((startingValue?: number, refreshRate?: number) => void) | undefined
?
Hi there, thanks for this nice component!
I'm running into a small issue or I might be overlooking something.
Here is an example of the problem:
https://codesandbox.io/s/long-wind-ud61h
If you click the Fake fetch
button, you will see that after the complete
method is called asynchronously, the continuous progress continues.
The fake fetch method basically does this:
this.LoadingBar.continuousStart(0);
setTimeout(() => this.complete(), 2000);
Am I missing something?
Hi there,
There's an issue introduced in your latest changes:
If the consumer does not use the ref
property, this line of code throws an exception on unmount, crashing the page.
Currently hacking it by replacing 100 with 99.99999 progress instead.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.