setTimeout function does not display HTML after function ends - javascript

I have created a timeout function for 3 seconds and after that time it is supposed to render the HTML. I'm following the official documentation to do this and the code is like on the documentation. Anyone has had a similar issue?
render() {
return (
<div>
{this.state.activePage === 'Home' ? setTimeout(function () {
<p>Hello World</p>
}, 3000) : null}
</div>
)
}

You should not write code like that in react. The setTimeout returns:
The returned timeoutID is a positive integer value which identifies
the timer created by the call to setTimeout(). T
and not the JSX which you returned from callback. But even if it did asynchronously return the JSX which you return from callback, you won't see the new content on the screen. To change UI in react you must change a state variable using setState which will cause a re render. Also render is not the place to call setState. You can call setState in useEffect for example.

It is not possible to return a value from the function passed to setTimeout.
Here are two options you could try
Create a state field to store the message you want to display and update the state from inside of the setTimeout. Also such an update cannot be done inside of the return. You would want to move this logic to a component mount function.
Here is a more vanilla JS approach to this issue using promise objects
Get return value from setTimeout
Also could you provide the document you are referring to for this code, so we can have a deeper dive onto the issue?

Related

Calling a method vs using a function to call a method

Suppose we have a method inside a class like this
class Blog extends Component {
postClicked = (id) => {
this.setState({selectedPostId: id})
}
render () {
const newPosts = this.state.posts.map(el => {
return <Post key={el.id}
title={el.title}
author={el.author}
onClick={this.postClicked(el.id)}/>
})
return
//something
{post}
}
}
}
Now, What is the difference between calling the handler like this
onClick={this.postClicked(el.id)} and onClick={() => this.postClicked(el.id)}
Would appreciate if someone can tell me the difference in general
after Ecmascript 6 javascript was introduced with is arrow function link
here ()==>{//code} is a similar as a function() or anonymous function
tell me if you find out what you want
The first option, "this.postClicked(el.id)", will actually call the method, "this.postClicked", with the "el.id" argument, each time the component renders (probably not what's intended).
The second option, "() => this.postClicked(el.id)", will only call the method, "this.postClicked", with the "el.id" argument, when "Post" is clicked.
Overall, if you can find a way to put the "el.id" argument into an "id" or "name" prop on the component
<Post id={el.id} />
then you can do:
<Post
id={el.id}
onClick={this.postClicked}
/>
this.postClicked = (event) => {
const { id } = event.target;
...
}
This last option avoids the use of an unnamed function. If you use an unnamed function, it will cause unnecessary re-renders. React cannot tell that an unnamed function is the same when it's checking whether or not it should re-render, by considering if the props of a component have changed. It considers the unnamed functions to be a new prop each time it checks, causing an unnecessary re-render each time.
Overall, it won't break your app, but it slows down performance slightly if you do it enough. It comes up especially if you start using React Motion (you'll really notice a difference there). It's best to avoid unnamed functions if possible.
you can read this blog it wil clear the things https://medium.com/#machnicki/handle-events-in-react-with-arrow-functions-ede88184bbb
Differences are,
First method is a wrong implementation and it wont give the intended result, where as second one will work.
In the first method you are making a function call, in second one you are assigning a function's signature to onClick.
It is like the combination of below two statements.
var variableName = function(){//some content};
onClick={variableName}
It looks like you question has already been answered. Just a side note though: remember that when assigning your method with an arrow function
onClick={ () => this.method() }
a new anonymous function is created on every re-render. So if the method doesn't need any arguments, it's better to reference the method directly (without parentheses so it's not invoked).
onClick={ this.method }
The first will call the function every time render is done.
The second will do what you want - call it onClick.

React keep to single setState call?

Supposed that in a function, i always need to set someState, and only need to set someOtherState if condition is true.
Is it preferable to do it like this:
this.setState({ someState });
if (condition) {
this.setState({ someOtherState });
}
Or this?
if (condition) {
this.setState({ someState, someOtherState });
} else {
this.setState({ someState });
}
I know React is optimized such that calling setState in quick succession will usually not result in a re-render. But is that behavior guaranteed or should the code make such assumption?
eg. supposed it works by re-rendering on a fixed time interval, if the first setState get called right before that interval block ends, then the second setState will result in a re-render?
Why don't you use ternary operator? If condition is true, set it to new state. Otherwise, use the old one.
this.setState(prevState => ({
someState,
someOtherState: condition ? newSomeOtherState : prevState.someOtherState
}))
React batches setState calls, so doing sequential update calls should only trigger one call to render.
You can assume that it will be batched provided you are within React managed event functions (React event system). For example, if it's an AJAX call, or some other delayed function like a promise or setTimeout, they will not be batched.
EDIT
This post has a pretty good summary of the order of events in most situations. You will find the state section about halfway down, but I'll try to summarise here:
Order goes :
Updating State
ShouldComponentUpdate

ComponentWillUpdate
Render
...
If you're calling multiple functions within one of these, React is smart enough to wait until they're complete before running the batched updates.
See the React docs here for details on setState:
(Link limit: facebook.github.io)/react/docs/react-component.html#setstate
and also a discussion on batching here:
https://groups.google.com/forum/#!topic/reactjs/G6pljvpTGX0

ReactJS - render called, but DOM not updated

This has happened to me a few times. I have always managed to work around the issue, yet I am still intrigued to understand why this happens, and what I have missed.
Essentially if I have a condition within my render method which specifies the class for my div:
let divClass = this.state.renderCondition ? 'red' : 'blue';
By default I set renderCondition within my state to false.
If I then define an onClick handler on a button (as follows), and click the button, whilst render IS called, the DOM is NOT updated. That is to say the class does not change.
onClickCompile: function() {
this.setState({renderCondition: true}, function() {
synchronousSlowFunction();
});
}
This seems to have something to do with running slow synchronous code in that if the code is quick and simple the DOM IS updated appropriately.
If I wrap the call to synchronousSlowFunction in a 500 millisecond timeout, everything works as expected. I would however like to understand what I have misunderstood such that I do not need this hack.
Can you share the button onClick code? I might be wrong but this looks like an incorrectly set button onClick listener.
Make sure that onClick callback is defined without (), i.e.
<button onClick={this.something} />
instead of:
<button onClick={this.something()} />
Post more code so we can get a better (bigger) picture
synchronousSlowFunction is as you mentioned synchronous. This means, that it blocks your component while it is running. That means, that react cannot update your component, because it has to wait for the callback function to complete until it can call render with the updated values. The setTimeout wrap makes the call asynchronous, so that react can render/update your component, while the function is doing its work. It is not the time delay, that makes it work but simply the callback, which is not render blocking. You could also wrap in in a Promise or make the slow function async to prevent render blocking.
Try something Like this:
this.setState((state) => ({
...state, renderCondition: true
}));
Maybe you're doing another setState for renderCondition some where the code above should fix such things.
or maybe try using PureComponent
import React, { PureComponent } from 'react'
export default class TablePreferencesModal extends PureComponent {
render() {
return (
<div>
</div>
)
}
}
After set state use this line
this.setState({})

How do I update the state (using ReactJS) if I should not call setState in componentWillUpdate?

When I setState in componentWillUpdate, componentWillUpdate runs in an infinite loop that doesn't stop getting triggered.
This never gives my render a chance to reflect my changes. How can I change the state if I shouldn't use componentWillUpdate?
Edit: I already have some understanding that setState should not be called in componentWillUpdate. I'm just confused what I should do as an alternative.
Edit #2: I started with componentWillReceiveProps but I can't seem to trigger this function when my Parent component changes state. I provide that state from the parent as a props to my child.
First thing to do is to check official documentation for this method (link). Where you can read when the function is actually called.
Then read common mistake(note):
You cannot use this.setState() in this method. If you need to update state in response to a prop change, use componentWillReceiveProps instead.
You change the state and React automatically calls componentWillUpdate.
I understand this is cautioned against in the guide but I am not sure I can see the problem with calling setState from within componentWillUpdate. True, it may result in infinite recursion unless of course you provide a bottom to that recursion (a way to break out of it). E.g. a way could be to check the second (nextState) parameter in componentWillUpdate and not invoke setState again if some condition is met (which is when the recursion ends).
As a minimal example, imagine a component that has no properties at all, only two pieces of state. Further imagine that the second piece of state is asynchronously obtained from the first. E.g. the first piece of state could be some parameter to provide to an Ajax call, and the second piece of state is the result of that call. So basically you call this.setState to configure the parameters and then inside componentWillUpdate you can do something like the following (to keep things simple I use a window.setTimeout as a placeholder for an Ajax call):
const ComponentWithAsyncState = React.createClass({
getInitialState: function() {
return {
ajaxParams: '',
ajaxResult: ''
};
},
setAjaxParams: function(params) {
this.setState({ajaxParams: params});
},
componentWillUpdate: function(_, nextState) {
if (nextState.ajaxParams!=this.state.ajaxParams)
window.setTimeout(function imagineThisIsAjax() {
this.setState({ajaxResult: `result from ${nextState.ajaxParams}`});
}.bind(this), 2000);
},
When, (e.g. through some controls managed by this component) the ajaxParams change, the sequence of actions will be something like (where ~~> denotes asynchronicity):
setAjaxParams --> this.setState --> componentWillUpdate ~~> imagineThisIsAjax --> this.setState --> componentWillUpdate
I.e. the second call to componentWillUpdate will not result in a further this.setState and thus the recursion will end there.

ReactJs: change state in response to state change

I've got a React component with an input, and an optional "advanced input":
[ basic ]
Hide Advanced...
[ advanced ]
The advanced on the bottom goes away if you click "Hide Advanced", which changes to "Show Advanced". That's straightforward and working fine, there's a showAdvanced key in the state that controls the text and whether the advanced input is rendered.
External JS code, however, might change the value of advanced, in which case I want to show the [advanced] input if it's currently hidden and the value is different than the default. The user should be able to click "Hide Advanced" to close it again, however.
So, someone external calls cmp.setState({advanced: "20"}), and I want to then show advanced; The most straightforward thing to do would just be to update showAdvanced in my state. However, there doesn't seem to be a way to update some state in response to other state changes in React. I can think of a number of workarounds with slightly different behavior, but I really want to have this specific behavior.
Should I move showAdvanced to props, would that make sense? Can you change props in response to state changes? Thanks.
Okay first up, you mention that a third party outside of your component might call cmp.setState()? This is a huge react no-no. A component should only ever call it's own setState function - nothing outside should access it.
Also another thing to remember is that if you're trying change state again in response to a state change - that means you're doing something wrong.
When you build things in this way it makes your problem much harder than it needs to be. The reason being that if you accept that nothing external can set the state of your component - then basically the only option you have is to allow external things to update your component's props - and then react to them inside your component. This simplifies the problem.
So for example you should look at having whatever external things that used to be calling cmp.setState() instead call React.renderComponent on your component again, giving a new prop or prop value, such as showAdvanced set to true. Your component can then react to this in componentWillReceiveProps and set it's state accordingly. Here's an example bit of code:
var MyComponent = React.createClass({
getInitialState: function() {
return {
showAdvanced: this.props.showAdvanced || false
}
},
componentWillReceiveProps: function(nextProps) {
if (typeof nextProps.showAdvanced === 'boolean') {
this.setState({
showAdvanced: nextProps.showAdvanced
})
}
},
toggleAdvancedClickHandler: function(e) {
this.setState({
showAdvanced: !this.state.showAdvanced
})
},
render: function() {
return (
<div>
<div>Basic stuff</div>
<div>
<button onClick={this.toggleAdvancedClickHandler}>
{(this.state.showAdvanced ? 'Hide' : 'Show') + ' Advanced'}
</button>
</div>
<div style={{display: this.state.showAdvanced ? 'block' : 'none'}}>
Advanced Stuff
</div>
</div>
);
}
});
So the first time you call React.renderComponent(MyComponent({}), elem) the component will mount and the advanced div will be hidden. If you click on the button inside the component, it will toggle and show. If you need to force the component to show the advanced div from outside the component simply call render again like so: React.renderComponent(MyComponent({showAdvanced: true}), elem) and it will show it, regardless of internal state. Likewise if you wanted to hide it from outside, simply call it with showAdvanced: false.
Added bonus to the above code example is that calling setState inside of componentWillReceiveProps does not cause another render cycle, as it catches and changes the state BEFORE render is called. Have a look at the docs here for more info: http://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
Don't forget that calling renderComponent again on an already mounted component doesn't mount it again, it just tells react to update the component's props and react will then make the changes, run the lifecycle and render functions of the component and do it's dom diffing magic.
Revised answer in comment below.
My initial wrong answer:
The lifecycle function componentWillUpdate will be ran when new state or props are received. You can find documentation on it here: http://facebook.github.io/react/docs/component-specs.html#updating-componentwillupdate
If, when the external setState is called, you then set showAdvanced to true in componentWillUpdate, you should get the desired result.
EDIT: Another option would be to have the external call to setState include showAdvanced: true in its new state.

Categories

Resources