Delay loading json data from local file into React JS - reactjs

I Map the Json Data in my Component Demo.js, I want to delay few seconds to display the data in my component. is there any way to do this? i read about setTimeout, but dont know to use it.

You can make use of state to show your data, and componentDidMount is best place to write setTimeout,
class App extends React.Component {
state={show:false}
componentDidMount(){
setTimeout(()=>{
this.setState({show:true})
},2000)
}
render() {
return <div>
{ this.state.show && <h1>Hello</h1>}
</div>;
}
}

setTimeout(() => { console.log("im delayed"); }, 5000); // delayed by 5sec

Related

ReactJs: Intial Component Rendering doesn't seems to work

I'm working on a project and came across this issue that first time when component is rendered, it doesn't shows anything on the screen. Then componentDidMount is invoked and after that something is visible on the screen.
My App Component
class App extends React.Component {
state={loading: true};
componentDidMount(){
alert("Inside did mount");
this.setState({loading: false});
}
render() {
alert(this.state.loading);
if (this.state.loading) {
return <div>Loading...</div>;
}
return(
<div>After ComponentDid Mount !</div>
)
}
}
In above code, initially Loading... should be visible on the screen for the first time. But this isn't happening.
Am I doing some kind of mistake here ?
Is there any way to show Loading... on the screen first and after that componentDidMount will run ?
your state for a class component needs to be inside a constructor.
constructor(props) {
super(props)
this.state = {your state}
}
Now that will allow you reference it as the component using (this)
It’s currently a normal variable and isn’t used as this.state but just state but that means changes to this variable may not reflect to changes to the pages. Further reading on this:
https://reactjs.org/docs/hooks-state.html
Also you may want to begin using functional components the way you wrote your render()
In my experience It’s preferable to have a single return in render and then from that return call upon functions and variables to render the page differently
It mounts the component fast so you can't see the loading text. You can use the setTimeout function to mimic remote server requests and latency.
import React from "react";
class App extends React.Component {
state = { loading: true };
componentDidMount() {
setTimeout(() => {
this.setState({ loading: false });
}, 5000);
}
render() {
if (this.state.loading) {
return <div>Loading...</div>;
}
return <div>After ComponentDid Mount !</div>;
}
}
export default App;

will puting function inside render method slow my app

i am learning react, i am django developer and i am getting data from api and is working fine, just for a fun i wanted to update data without clicking reload, so what i did is put fetch function inside render which is looping , and it is giving real time feel, but i want to know that will doing this like this slow my app like in vannila js, since it is rendering again and again, but since react uses virtual dom i have soft side on this technique
import React from 'react';
class FetchRandomUser extends React.Component {
constructor(){
super();
this.state = {
data: [],
};
}
fetchdata(){
fetch('http://127.0.0.1:8000/api')
.then(response=>response.json())
.then((data)=>{
this.setState({
data:data,
});
console.log(data);
});
}
componentDidMount(){
this.fetchdata();
}
render() {
this.fetchdata();
const dat = this.state.data;
const rows = dat.map((emp)=>
<div>
<h1>{emp.id}</h1>
<h1>{emp.title}</h1>
<h1>{emp.body}</h1>
</div>
);
return (
<div>
{rows}
</div>
)
}
}
export default FetchRandomUser;
You shouldn't use fetch inside render method. Because in your code when this.fetchData() is run, as you can see you are setting the state in that method using setState(), and setState itself calls render method so your code will result in an infinite loop.
Also You shouldn't use fetch inside render method because every time render is called your fetchData() will run which will slow your program as it takes time to fetch data from a server.

React Isomorphic Rendering - handle window resize event

I would like to set the state of a component based on the current size of the browser window. The server-side rendering has been used (React+Redux). I was thinking about using the Redux store as a glue - just to update the store on resize.
Is there any other/better solution that doesn't involve Redux.
Thanks.
class FocalImage extends Component {
// won't work - the backend rendering is used
// componentDidMount() {
// window.addEventListener(...);
//}
//componentWillUnmount() {
// window.removeEventListener('resize' ....);
//}
onresize(e) {
//
}
render() {
const {src, className, nativeWidth, nativeHeight} = this.props;
return (
<div className={cn(className, s.focalImage)}>
<div className={s.imageWrapper}>
<img src={src} className={_compare_ratios_ ? s.tall : s.wide}/>
</div>
</div>
);
}
}
I have a resize helper component that I can pass a function to, which looks like this:
class ResizeHelper extends React.Component {
static propTypes = {
onWindowResize: PropTypes.func,
};
constructor() {
super();
this.handleResize = this.handleResize.bind(this);
}
componentDidMount() {
if (this.props.onWindowResize) {
window.addEventListener('resize', this.handleResize);
}
}
componentWillUnmount() {
if (this.props.onWindowResize) {
window.removeEventListener('resize', this.handleResize);
}
}
handleResize(event) {
if ('function' === typeof this.props.onWindowResize) {
// we want this to fire immediately the first time but wait to fire again
// that way when you hit a break it happens fast and only lags if you hit another break immediately
if (!this.resizeTimer) {
this.props.onWindowResize(event);
this.resizeTimer = setTimeout(() => {
this.resizeTimer = false;
}, 250); // this debounce rate could be passed as a prop
}
}
}
render() {
return (<div />);
}
}
Then any component that needs to do something on resize can use it like this:
<ResizeHelper onWindowResize={this.handleResize} />
You also may need to call the passed function once on componentDidMount to set up the UI. Since componentDidMount and componentWillUnmount never get called on the server this works perfectly in my isomorphic App.
My solution is to handle resize event on the top-most level and pass it down to my top-most component, you can see full code here, but the gist is:
let prevBrowserWidth
//re-renders only if container size changed, good place to debounce
let renderApp = function() {
const browserWidth = window.document.body.offsetWidth
//saves re-render if nothing changed
if (browserWidth === prevBrowserWidth) {
return
}
prevBrowserWidth = browserWidth
render(<App browserWidth={browserWidth} />, document.getElementById('root'))
}
//subscribing to resize event
window.addEventListener('resize', renderApp)
It obviously works without Redux (while I still use Redux) and I figured it would be as easy to do same with Redux. The advantage of this solution, compared to one with a component is that your react components stay completely agnostic of this and work with browser width as with any other props passed down. So it's a localized place to handle a side-effect. The disadvantage is that it only gives you a property and not event itself, so you can't really rely on it to trigger something that is outside of render function.
Besides that you can workaround you server-side rendering issue by using something like:
import ExecutionEnvironment from 'exenv'
//...
componentWillMount() {
if (ExecutionEnvironment.canUseDOM) {
window.addEventListener(...);
}
}

State is not updating in componentWillMount

When i am trying to update the state of react component from an api call in componentwillmount function it is not working as expected. The value is not getting set.
export default class ListOfProducts extends Component {
componentWillMount() {
console.log('component currently mounting');
fetchOrder().then(data => {
console.log('order api call has been finished.', data);
this.setState(data, function() {
//this should print new data but i am still getting old data
console.log('current this.state.', this.state.orders)
})
})
}
constructor(props) {
super(props);
this.state = {
"orders": {
"order_items": []
}
};
}
render() {
let productList = [];
let productUnit = (
<View>
{this.state.orders.order_items.map(function(order,i){
return <ProductListItem
delivered={true}
productSKU={3}/>
})}
</View>
);
return productUnit;
}
}
If you want to perform any asynchronous requests, I suggest you perform them in the componentDidMount lifecycle method. This is the suggested path based on the Reactjs documentation for componentDidMount.
Invoked once, only on the client (not on the server), immediately
after the initial rendering occurs. At this point in the lifecycle,
you can access any refs to your children (e.g., to access the
underlying DOM representation). The componentDidMount() method of
child components is invoked before that of parent components.
If you want to integrate with other JavaScript frameworks, set timers
using setTimeout or setInterval, or send AJAX requests, perform those
operations in this method.
Perhaps you need to change:
" extends Component { "
to
" extends React.Component { "

componentWillUnmount() not being called when refreshing the current page

I've been having this problem where my code in the componentDidMount() method wasn't firing properly when refreshing the current page (and subsequently, the component). However, it works perfectly fine just navigating and routing through my website by clicking links. Refresh the current page? Not a chance.
I found out that the problem is that componentWillUnmount() doesn't trigger when I refresh the page and triggers fine clicking links and navigating my website/app.
The triggering of the componentWillUnmount() is crucial for my app, since the data that I load and process in the componentDidMount() method is very important in displaying information to users.
I need the componentWillUnmount() to be called when refreshing the page because in my componentWillMount() function (which needs to re-render after every refresh) I do some simple filtering and store that variable in a state value, which needs to be present in the logos state variable in order for the rest of the component to work. This does not change or receive new values at any time during the component's life cycle.
componentWillMount(){
if(dataReady.get(true)){
let logos = this.props.questions[0].data.logos.length > 0 ? this.props.questions[0].data.logos.filter((item) => {
if(item.logo === true && item.location !== ""){
return item;
}
}) : [];
this.setState({logos: logos});
}
};
Cliffs:
I do DB filtering in componentWillMount()method
Need it to be present in the component after refresh
But I have a problem where the componentWillUnmount() doesn't trigger when the page is refreshed
Need help
Please
When the page refreshes react doesn't have the chance to unmount the components as normal. Use the window.onbeforeunload event to set a handler for refresh (read the comments in the code):
class Demo extends React.Component {
constructor(props, context) {
super(props, context);
this.componentCleanup = this.componentCleanup.bind(this);
}
componentCleanup() { // this will hold the cleanup code
// whatever you want to do when the component is unmounted or page refreshes
}
componentWillMount(){
if(dataReady.get(true)){
let logos = this.props.questions[0].data.logos.length > 0 ? this.props.questions[0].data.logos.filter((item) => {
if(item.logo === true && item.location !== ""){
return item;
}
}) : [];
this.setState({ logos });
}
}
componentDidMount(){
window.addEventListener('beforeunload', this.componentCleanup);
}
componentWillUnmount() {
this.componentCleanup();
window.removeEventListener('beforeunload', this.componentCleanup); // remove the event handler for normal unmounting
}
}
useWindowUnloadEffect Hook
I've extracted the code to a reusable hook based on useEffect:
// The hook
const { useEffect, useRef, useState } = React
const useWindowUnloadEffect = (handler, callOnCleanup) => {
const cb = useRef()
cb.current = handler
useEffect(() => {
const handler = () => cb.current()
window.addEventListener('beforeunload', handler)
return () => {
if(callOnCleanup) handler()
window.removeEventListener('beforeunload', handler)
}
}, [callOnCleanup])
}
// Usage example
const Child = () => {
useWindowUnloadEffect(() => console.log('unloaded'), true)
return <div>example</div>
}
const Demo = () => {
const [show, changeShow] = useState(true)
return (
<div>
<button onClick={() => changeShow(!show)}>{show ? 'hide' : 'show'}</button>
{show ? <Child /> : null}
</div>
)
}
ReactDOM.render(
<Demo />,
root
)
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
I also run into this problem and realised that I needed to make sure that at least 2 components will always gracefully unmount. So I finally did a High Order Component that ensures the wrapped component is always unmounted
import React, {Component} from 'react'
// this high order component will ensure that the Wrapped Component
// will always be unmounted, even if React does not have the time to
// call componentWillUnmount function
export default function withGracefulUnmount(WrappedComponent) {
return class extends Component {
constructor(props){
super(props);
this.state = { mounted: false };
this.componentGracefulUnmount = this.componentGracefulUnmount.bind(this)
}
componentGracefulUnmount(){
this.setState({mounted: false});
window.removeEventListener('beforeunload', this.componentGracefulUnmount);
}
componentWillMount(){
this.setState({mounted: true})
}
componentDidMount(){
// make sure the componentWillUnmount of the wrapped instance is executed even if React
// does not have the time to unmount properly. we achieve that by
// * hooking on beforeunload for normal page browsing
// * hooking on turbolinks:before-render for turbolinks page browsing
window.addEventListener('beforeunload', this.componentGracefulUnmount);
}
componentWillUnmount(){
this.componentGracefulUnmount()
}
render(){
let { mounted } = this.state;
if (mounted) {
return <WrappedComponent {...this.props} />
} else {
return null // force the unmount
}
}
}
}
Note: If like me, you are using turbolinks and rails, you might wanna hook on both beforeunload and turbolinks:before-render events.
I see that this question has over a thousand views, so I'll explain how I solved this problem:
To solve this particular problem, the most sensible way is to create an upper level component that loads your subscription or database, so that you load the required data before passing it to your child component, which would completely remove the need to use componentWillMount(). Also, you can do the computations in the upper level component and just pass them down as props to use in your receiving component
For example:
class UpperLevelComponent extends React.Component {
render() {
if(this.props.isReady) {
return(<ChildComponent {...props}/>)
}
}
}
export default createContainer(() => {
const data = Meteor.subscribe("myData");
const isReady = data.ready();
return {
isReady,
data: MyData.find.fetch()
}
})
In the example above, I use Meteor's reactive container to get my MongoDB data and wait for it to completely finish subscribing before I render the child component, passing it any props I want. If you load all your data in the higher level component, you won't have to rely on the componentWillMount() method to trigger after every refresh. The data will be ready in the upper level component, so you can use it however you want in the child component.

Resources