Setting State Between Radio Buttons - reactjs

An example of the issue is found on CodeSandBox. Am I short circuiting myself between TRUE/FALSE values?
Can someone please help explain why the state variable isOptionOne is not being set as expected? Upon calling setIsOptionOne I would think that I can use isOptionOne in the remaining lines of code of the function. Unfortunately, that does not seem to be the case. To verify, see the console.log output. The two values for isDefault and isOptionOne should match.
Where am I going wrong? Thank you.

That is the expected behavior. React batches the state updates, which means it doesn't immediately update the state and re-render everything after each setState method call. From official documentation:
setState() enqueues changes to the component state and tells React
that this component and its children need to be re-rendered with the
updated state. This is the primary method you use to update the user
interface in response to event handlers and server responses.
Think of setState() as a request rather than an immediate command to
update the component. For better perceived performance, React may
delay it, and then update several components in a single pass. React
does not guarantee that the state changes are applied immediately.
setState() does not always immediately update the component. It may
batch or defer the update until later. This makes reading this.state
right after calling setState() a potential pitfall. Instead, use
componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update
has been applied. If you need to set the state based on the previous
state, read about the updater argument below.
Additionally, the above document is for the traditional class component's setState API. If you want to detect a change in your hook-based state, use useEffect.

Related

React onclick pass button api id to state

I have a simple aip with an array with 4 different ids. In react I've made an <ul> with a button for each of the ids. When I click the button, I want to change the state.id and console.log the new state.id with the new specific button id value from the api (eventually I want to change some render depending on the button I press).
I need to press two times on one of the buttons to console.log my desired id, I need the state to change on the first click (to make some changes to some new render).
From the React docs for setState()
Think of setState() as a request rather than an immediate command to
update the component. For better perceived performance, React may
delay it, and then update several components in a single pass. React
does not guarantee that the state changes are applied immediately.
Try logging this.state inside your render function and you will see how it actually IS happening after the first click - but your log is displaying it before the state updates.
setState() : setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied.

Why don't redux actions "break" componentDidMount/useEffect?

A component will rerender when one of its props changes. That's sort of the whole point of React.
A component that's subscribed to a slice of Redux state will rerender when that state changes. That's sort of the whole point of Redux. And when you use the connect api, those slices of state are simply props, so it goes straight to my first point.
SO, what I'm wondering is:
// only executes once, on mount, right?
componentDidMount() {
this.something()
this.props.someReduxActionThatModifiesAnotherPropInThisComponent()
this.somethingElse()
}
Since the redux action changes the prop, and the component rerenders, I would think that componentDidMount has had its day and now it's done, and we'll never run this.somethingElse().
Obviously I am wrong about this. I know. Can someone tell me what it is that makes this work? What is the whole flow here? I imagine the answer is maybe simply that a component doesn't rerender from inside CDM?
And is it any different in useEffect?
You are correct that componentDidMount only runs once. You are also correct that dispatching a redux action from within the method will trigger a re-render if your component is subscribed.
I think the confusion is about when a re-render occurs.
Updating state only informs React that a re-render is required, it does not pause execution and re-render immediately.
Because of this, the lifecycle method will complete execution of the entire method, and the run the scheduled re-render after.
This is related to why you also cannot use the updated state immediately after calling this.setState (or dispatch in Redux). Because the state is not updated instantly, you've only informed it that an update is required. Behind the scenes, React batches and performs the updates, and then determines what re-renders to perform.
The same is true about Function components and useEffect.
componentDidMount runs only once during the mounting process. But even if you replaced componentDidMount with componentDidUpdate, it also wouldn't rerender before executing the whole function.
The reason to this is that it is actually up to React when to re-render. Sometimes, in situations like yours, React decides not to re-render the component immediately and postpone it.
A similar situation would be when same setState functions are called inside a method. The first setState call doesn't force an immediate re-render.

componentDidMount does show intermediate state even though React docs suggest otherwise

1st premise:
componentDidMount() is invoked immediately after a component is mounted (inserted into the tree).
2nd premise:
You may call setState() immediately in componentDidMount(). It will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state.
both from https://reactjs.org/docs/react-component.html#componentdidmount
My conclusion:
Based on the above, mounting cannot be the last step in displaying to the browser, otherwise what is rendered and mounted (any intermediate state) before componentDidMount will always be shown.
However, based on my experience, I've found that any state specified in the constructor does in fact get shown before any overriding state changes in componentDidMount.
This is suggesting to me that premise 2 is incorrect. My conclusion is therefore incorrect as well. Mounting must be the final step in displaying to the browser.
Can anyone clear this up for me?
I believe if you set the state in componentDidMount synchronously, the new state will be the only one shown (or at least the switch would happen so fast after rendering it would be impossible to detect).
If you're trying to set it asynchronously, such as using results from a fetch, then you would see the initial state until the async call is completed.

React state update while rendering

I need to update a state in my react app while rendering the content. Is there any option to update state while rendering.
Note: I am very new to react
You can use componentDidUpdate() Lifecycle method.
and inside componentDidUpdate() function update your state.
FYI: componentDidUpdate() calls every time if component gets updtated.
https://reactjs.org/docs/react-component.html
Futureproofing Note: answer relevant to v16.4.
The answer to your question depends on what you mean by saying "while rendering".
When react invokes the render method of a component, it does not really render anything, yet. The results of the render method will undergo "reconciliation", which means that it will be compared to what's rendered at the moment. If a difference is detected, react will actually re-render the DOM, as effectively as it can.
This means that you can not do anything when react is actually rendering / re-rendering the DOM, since your code is not being executed.
You can, however, do something after the render method has been invoked.
As others have stated before me, the componentDidUpdate method is the place.
Note that the fact that this method has been invoked does not necessarily mean react has re-rendered the DOM. It only assures that the component is in sync with the DOM.
Do note that since setting state CAN cause a re-render, so you should really be careful about setting state in componentDidUpdate - or you might cause an infinite loop of sorts.
Even if you correctly implement shouldComponentUpdate, stopping the render cycle from ever reaching cDU- react docs suggest the result of sCU can be taken as a hint in the future, which will break your app in future releases.
So, if you must setState in cDU - you must check that this setState is required, and is not a side-effect of setting the state in the first place.

Props updated, componentDidUpdate did not fire

Is there ever a situation where componentDidUpdate would NOT fire, even if the props updated in React?
There are 3 conditions that can cause componentDidUpdate to not fire:
1) You wrote a custom shouldComponentUpdate that returned false.
2) The internal react methods determined that there was no change in the virtual DOM, so it chose not to re-render.
3) You extended something other than React.Component (such as PureComponent) which has a default shouldComponentUpdate method that returned false.
You can suppress a render with returning false in shouldComponentUpdate().
So yes, in that case componentDidUpdate() won't fire.
this can also happen, if your component is in a list and the key of your component changes (ie. on every render) or the key is missing, or the key is duplicate, etc.
refer to docs for details:
https://reactjs.org/docs/lists-and-keys.html
A common situation where this occurs is when multiple prop changes occur which don't effect anything in the virtual DOM.
For example you may wish to display a success message if an API returns 200 status code, with props that change like this:
API not called:
this.props.apiState == false
API called:
this.props.apiState == 'loading'
API successful:
this.props.apiState == 'success'
In this situation componentDidUpdate will only fire once, and if you console log this.props.apiState at the time it is fired you will see that it is loading. So any trigger in componentDidUpdate that is waiting on success will not occur.
ComponentWillReceiveProps deals with this issue in older versions of React, and in newer versions of React you can use shouldComponentUpdate to force an update when your desired prop change occurs.
Nathan response is correct but it did not solve my problem when I searched for the same answers.
Sometimes it looks like props are updated but it is whole new component rendered with different props. Check componentDidMount (add console.log in it for example) to see what exactly happens.

Resources