I am using the following code:
handleOwnerMode = ownerChecked => {
this.setState(prev => ({ ownerChecked, showOwner: !prev.showOwner}))
// this.setState(prev => ({ ownerChecked: !prev.ownerChecked, showOwner: !prev.showOwner }))
}
Inside the render is
<Switch onChange={this.handleOwnerMode} checked={this.state.ownerChecked} />
OnChange, I somehow was able to receive what was changed about ownerChecked. Why is this the case? I didn't write onChange={this.handleOwnerMode(event.value)} or anything like that...
Also, for setState. I normally just use this.setState( { state: newState} ), but now I can somehow pass in the previous state with this.setState( prev => {} ). Is there defined overloading somewhere that lets me do this?
Thank you.
OnChange, I somehow was able to receive what was changed about
ownerChecked. Why is this the case? I didn't write
onChange={this.handleOwnerMode(event.value)} or anything like that...
In both cases you have passed a function (callback) to "receivers". First time to Switch Component, second time to React. Each of them can call your function/callback using any parameter they want. This is how normally callbacks are used.
Is there defined overloading somewhere that lets me do this?
Yeah probably setState checks if you passed a function to it and behaves differently: e.g. gives you previous state and calls your function. If you pass an object to it, it doesn't do that.
React events are synthetic so that even when yo do not pass any event parameters, function takes it. Take a look at these. More information 1, More information 2.
Related
I'm reading Forms section of reactjs documentation and just tried this code to demonstrate onChange usage (JSBIN).
var React= require('react');
var ControlledForm= React.createClass({
getInitialState: function() {
return {
value: "initial value"
};
},
handleChange: function(event) {
console.log(this.state.value);
this.setState({value: event.target.value});
console.log(this.state.value);
},
render: function() {
return (
<input type="text" value={this.state.value} onChange={this.handleChange}/>
);
}
});
React.render(
<ControlledForm/>,
document.getElementById('mount')
);
When I update the <input/> value in the browser, the second console.log inside the handleChange callback prints the same value as the first console.log, Why I can't see the result of this.setState({value: event.target.value}) in the scope of handleChange callback?
From React's documentation:
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value. There is no
guarantee of synchronous operation of calls to setState and calls may
be batched for performance gains.
If you want a function to be executed after the state change occurs, pass it in as a callback.
this.setState({value: event.target.value}, function () {
console.log(this.state.value);
});
As mentioned in the React documentation, there is no guarantee of setState being fired synchronously, so your console.log may return the state prior to it updating.
Michael Parker mentions passing a callback within the setState. Another way to handle the logic after state change is via the componentDidUpdate lifecycle method, which is the method recommended in React docs.
Generally we recommend using componentDidUpdate() for such logic instead.
This is particularly useful when there may be successive setStates fired, and you would like to fire the same function after every state change. Rather than adding a callback to each setState, you could place the function inside of the componentDidUpdate, with specific logic inside if necessary.
// example
componentDidUpdate(prevProps, prevState) {
if (this.state.value > prevState.value) {
this.foo();
}
}
You could try using ES7 async/await. For instance using your example:
handleChange: async function(event) {
console.log(this.state.value);
await this.setState({value: event.target.value});
console.log(this.state.value);
}
Watch out the react lifecycle methods!
http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
https://reactjs.org/docs/react-component.html
I worked for several hours to find out that getDerivedStateFromProps will be called after every setState().
😂
Sometime this issue occurs with state.
In case of hooks, you should use useEffect hook, As below-
const [fruit, setFruit] = useState('');
setFruit('Apple');
useEffect(() => {
console.log('Fruit', fruit);
}, [fruit])
This saved my day, Hope will help you!!!
Accessing this.state after calling the setState method is not guaranteed to return the updated status due to the asynchronous nature of setState.
To guarantee an update after calling setState, there are two solutions you may pursue.
Solution 1: As mentioned in one of the above answers, put your code in the componentDidUpdate method
Solution 2: As mentioned in another of the above answers, pass your stuff as a callback
this.setState({value: myValue}, function () {
this.functionThatIsExecutedWhenStateIsUpdated();
});
It's important to note that these two solutions are not clearly interchangeable. The one cannot easily solve all the use-cases of the other. As a general rule, if you can, best practice says that solution 1 is preferred. But, there are use-cases where only solution 2 "more effectively" works such as the "update-my-view-and-post-my-data" use case. This use case goes like this:
After adding an item, say, "Add Schedule", I want to both add that item to a front-end list and immediately post the just-updated-list to the backend, as demonstrated in the concept below:
If you dont do either solution, i.e. if you only say this in your code:
addToItemArray = () => {
this.setState{{ scheduledItemsArray: newObjectListWithMax}}
this.postData();
}
<button className="btn btn-secondary btn-block" onClick={this.addToItemArray}>Add Shedule</button>
... you will post the list excluding the "Delivery to Max" item, because the state wont be updated when you this.postData() (again, because its asynchronous).
If you utilise solution 1, you would make a POST after typing in every character in the Schedule Name textbox!
There are other ways aswell to cater for this use-case but solution 2 best conveys the intent when reading the code.
Given the ubiquitous nature of this use case in virtually every web app, the callback technique explained by Michael's answer is an indispensable piece of code in every developers toolkit.
async-await syntax works perfectly for something like the following...
changeStateFunction = () => {
// Some Worker..
this.setState((prevState) => ({
year: funcHandleYear(),
month: funcHandleMonth()
}));
goNextMonth = async () => {
await this.changeStateFunction();
const history = createBrowserHistory();
history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
goPrevMonth = async () => {
await this.changeStateFunction();
const history = createBrowserHistory();
history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
React bathces different set state calls so that it can determine what is the most optimal strategy for rerendering the website is going to be.
Imagine you have an application where you have a lot of different components. Perhaps, with one button click you are updating the state in multiple components, not just on the current one. In this case, React does not want to just completely isolate and do all those different updates independently.
React wants to figure out if it can stack all these updates together, maybe there is a more optimal way of updating these components so that it is more performant. This is what React is doing behind the scenes. As a result, set state call is asynchronous call.
Simply putting - this.setState({data: value}) is asynchronous in
nature that means it moves out of the Call Stack and only comes back
to the Call Stack unless it is resolved.
Please read about Event Loop to have a clear picture about Asynchronous nature in JS and why it takes time to update -
https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4
Hence -
this.setState({data:value});
console.log(this.state.data); // will give undefined or unupdated value
as it takes time to update.
To achieve the above process -
this.setState({data:value},function () {
console.log(this.state.data);
});
please take a look at this code below
basically what is happening my action is being dispatched here:
useEffect(() => {
fetchData()
setLoaded(true)
}, [])
but for some reason this is infinite looping and causing my action to be dispatched continuously
export const fetchData = () => ({ type: 'GET_USER_DATA' })
and this is triggering my epic
const getUserData = (action$, state$) =>
action$.pipe(
ofType('GET_USER_DATA'),
mergeMap(
(action) =>
ajax
.getJSON(
`myurlishere`,
)
.pipe(map((response) => fetchUserFulfilled(response))),
)
)
which trigger this:
const fetchUserFulfilled = (payload) => ({ type: 'GET_DATA_SUCCESS', data: payload })
this code all works but it's continuously calling it in an infinite loop
however, if I move the code from useEffect to a button call like so:
<button onClick={fetchData}>fetch</button>
it only calls it once, which is what I want
but I need the data to be called onmount. so how do I fix it?
please note I have tried adding various things to the second argument of useEffect but it's having no effect
useEffect(() => {
fetchData()
setLoaded(true)
}, [user.id])
Based solely off the provided code, I don't see any issues. My gut suggest a few options, even though you mentioned some of them I would triple check:
Missing dependencies array as second arg to useEffect, or you're using a variable for it but the variable has an undefined value which would have the same problem.
If you are using useEffect dependencies, perhaps one of them is constantly changing unknowingly. e.g. objects often change in identity between renders, {} !== {}
There is code not shown that is also dispatching the same action, and in fact that useEffect is only running once.
Some parent is rendering one of the ancestors or this component with a key={something} and the value provided changes on each render. If that happens, the component is torn down and recreated every time from scratch.
If you are 100% positive you are providing useEffect(work, []), an empty array as second argument, but the effect is in fact confirmed to be running in an infinite loop, synchronously, then the forth possibility is likely.
If you typed these code examples in the question by hand when posting this, do not trust that you implemented them the same way as what you think your app is doing. Triple check. Ideally have someone else check who didn't write the code. Often the problem is what we think we've told our code to do is not what we've actually told it to do. If you haven't already, your best bet is to step through the code with a debugger so you can see what's happening.
Hope this helps!
this is the code now working:
export const getUserDataEpic = () => {
return ajax
.getJSON(myurl)
.pipe(
map((response) => fetchUserFulfilled(response)),
)
}
I know I'm not listening to the action fired now, but why would that be causing an infinite loop?
I'm reading Forms section of reactjs documentation and just tried this code to demonstrate onChange usage (JSBIN).
var React= require('react');
var ControlledForm= React.createClass({
getInitialState: function() {
return {
value: "initial value"
};
},
handleChange: function(event) {
console.log(this.state.value);
this.setState({value: event.target.value});
console.log(this.state.value);
},
render: function() {
return (
<input type="text" value={this.state.value} onChange={this.handleChange}/>
);
}
});
React.render(
<ControlledForm/>,
document.getElementById('mount')
);
When I update the <input/> value in the browser, the second console.log inside the handleChange callback prints the same value as the first console.log, Why I can't see the result of this.setState({value: event.target.value}) in the scope of handleChange callback?
From React's documentation:
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value. There is no
guarantee of synchronous operation of calls to setState and calls may
be batched for performance gains.
If you want a function to be executed after the state change occurs, pass it in as a callback.
this.setState({value: event.target.value}, function () {
console.log(this.state.value);
});
As mentioned in the React documentation, there is no guarantee of setState being fired synchronously, so your console.log may return the state prior to it updating.
Michael Parker mentions passing a callback within the setState. Another way to handle the logic after state change is via the componentDidUpdate lifecycle method, which is the method recommended in React docs.
Generally we recommend using componentDidUpdate() for such logic instead.
This is particularly useful when there may be successive setStates fired, and you would like to fire the same function after every state change. Rather than adding a callback to each setState, you could place the function inside of the componentDidUpdate, with specific logic inside if necessary.
// example
componentDidUpdate(prevProps, prevState) {
if (this.state.value > prevState.value) {
this.foo();
}
}
You could try using ES7 async/await. For instance using your example:
handleChange: async function(event) {
console.log(this.state.value);
await this.setState({value: event.target.value});
console.log(this.state.value);
}
Watch out the react lifecycle methods!
http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
https://reactjs.org/docs/react-component.html
I worked for several hours to find out that getDerivedStateFromProps will be called after every setState().
😂
Sometime this issue occurs with state.
In case of hooks, you should use useEffect hook, As below-
const [fruit, setFruit] = useState('');
setFruit('Apple');
useEffect(() => {
console.log('Fruit', fruit);
}, [fruit])
This saved my day, Hope will help you!!!
Accessing this.state after calling the setState method is not guaranteed to return the updated status due to the asynchronous nature of setState.
To guarantee an update after calling setState, there are two solutions you may pursue.
Solution 1: As mentioned in one of the above answers, put your code in the componentDidUpdate method
Solution 2: As mentioned in another of the above answers, pass your stuff as a callback
this.setState({value: myValue}, function () {
this.functionThatIsExecutedWhenStateIsUpdated();
});
It's important to note that these two solutions are not clearly interchangeable. The one cannot easily solve all the use-cases of the other. As a general rule, if you can, best practice says that solution 1 is preferred. But, there are use-cases where only solution 2 "more effectively" works such as the "update-my-view-and-post-my-data" use case. This use case goes like this:
After adding an item, say, "Add Schedule", I want to both add that item to a front-end list and immediately post the just-updated-list to the backend, as demonstrated in the concept below:
If you dont do either solution, i.e. if you only say this in your code:
addToItemArray = () => {
this.setState{{ scheduledItemsArray: newObjectListWithMax}}
this.postData();
}
<button className="btn btn-secondary btn-block" onClick={this.addToItemArray}>Add Shedule</button>
... you will post the list excluding the "Delivery to Max" item, because the state wont be updated when you this.postData() (again, because its asynchronous).
If you utilise solution 1, you would make a POST after typing in every character in the Schedule Name textbox!
There are other ways aswell to cater for this use-case but solution 2 best conveys the intent when reading the code.
Given the ubiquitous nature of this use case in virtually every web app, the callback technique explained by Michael's answer is an indispensable piece of code in every developers toolkit.
async-await syntax works perfectly for something like the following...
changeStateFunction = () => {
// Some Worker..
this.setState((prevState) => ({
year: funcHandleYear(),
month: funcHandleMonth()
}));
goNextMonth = async () => {
await this.changeStateFunction();
const history = createBrowserHistory();
history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
goPrevMonth = async () => {
await this.changeStateFunction();
const history = createBrowserHistory();
history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}
React bathces different set state calls so that it can determine what is the most optimal strategy for rerendering the website is going to be.
Imagine you have an application where you have a lot of different components. Perhaps, with one button click you are updating the state in multiple components, not just on the current one. In this case, React does not want to just completely isolate and do all those different updates independently.
React wants to figure out if it can stack all these updates together, maybe there is a more optimal way of updating these components so that it is more performant. This is what React is doing behind the scenes. As a result, set state call is asynchronous call.
Simply putting - this.setState({data: value}) is asynchronous in
nature that means it moves out of the Call Stack and only comes back
to the Call Stack unless it is resolved.
Please read about Event Loop to have a clear picture about Asynchronous nature in JS and why it takes time to update -
https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4
Hence -
this.setState({data:value});
console.log(this.state.data); // will give undefined or unupdated value
as it takes time to update.
To achieve the above process -
this.setState({data:value},function () {
console.log(this.state.data);
});
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.
So i am having tough time figuring/understanding the correct way to call method inside a class in javascript for example
consider we have stateful component with various method like
addIngredientHandler = (type) => { //Adds one to the state of ingredient }
and
purchasingHandlerOpen = () => this.setState({purchasing: true}) //will show a order summary pop-up if we have more than one ingredient
We pass both of them to child component (using props) by calling them in a return of our stateful component like this
<BuildControls
ingredientAdded={this.addIngredientHandler}
purchasingHandlerOpen={this.purchasingHandlerOpen}
purchasableHandler={this.state.purchasable} />
and In our stateless child component we do
<BuildControl
ingredientAdded={() => props.ingredientAdded(el.type)}
/>))}
<button className={Classes.OrderButton} disabled={!props.purchasableHandler} onClick={props.purchasingHandlerOpen}>Order</button>
</div
Here we have use this at one place
ingredientAdded={() => props.ingredientAdded(el.type)}
and this in another
onClick={props.purchasingHandlerOpen}>
So my question is when do we call a method/function using {() => props.ingredientAdded(el.type)} and when do we use {props.purchasingHandlerOpen} and when do we probably do something like {props.purchasingHandlerOpen()}
Slight Note: In the above example where i do
<button className={Classes.OrderButton} disabled={!props.purchasableHandler} onClick={props.purchasingHandlerOpen}>Order</button>
If I do something like {props.purchasingHandlerOpen()} it throws infinite render error message, I I do something like {() => props.purchasingHandlerOpen} the button does not work.
First of all, you have to understand that the thing you're passing here are just functions, so there is nothing principally different in those 2 ways
There are few points you need to consider though:
First: since react.js uses shallow comparison, every time you're passing
ingredientAdded={() => props.ingredientAdded(el.type)}
you're actually pass function created just now, so it may cause unneeded calls of your children render function (you could easily avoid this by using shouldComponentUpdate though). This could lead to possible performance issues on big react trees so that you second approach is preferred.
Second: you could easily mix a some value via your first approach, something like
ingredientAdded={() => props.ingredientAdded(el.type, SOMETHING_FROM_STATE)}
Third. You can easily modify your event handlers and pass down them in react tree by generating functions which return functions:
class App extends React.Component {
generateFunction(something) {
return (arg) => {
this.props.myFunction(something, arg)
}
}
render() {
return (
<div>
<FirstComponent onClick={this.generateClickFunction('First')} />
<SecondComponent onClick={this.generateClickFunction('Second')} />
</div>
}
}
}
UPD
onClick should always receive function, not its results, like that:
<button ... onClick={props.purchasingHandlerOpen} />
if you are changing onClick to {props.purchasingHandlerOpen()} you are calling the function, so you're passing its result to props.
If you are changing onClick to {() => purchasingHandlerOpen} you are passing undefined (it's not a props.purchasingHandlerOpen, but purchasingHandlerOpen is undefined) so that React considers there is no a callback passed to the props
{() => props.ingredientAdded(el.type)} creates a new funciton which binds the el.type, see arrow functions
{props.purchasingHandlerOpen} does nothing since we do not execute the function (there are no (), call, apply). We simply pass the function reference.
{props.purchasingHandlerOpen()} runs the function.