Radio Buttons & setState in React
Radio buttons, onChange events, setting state & asynchronicity in React
I recently worked on a project that had two radio buttons in React. I needed to have the functionality that when a user clicks one or the other, it shows “checked”, and the state gets updated so the data on the page would sort by whichever option was chosen. I ran into some issues and learned some things about how radio buttons work with an onChange event listener and how setState is an asynchronous function and how to work with that. Below is how I approached the solution.
1. Starting with 2 radio buttons, neither is checked, and neither will show “checked” or “filled” when clicked:
2. Add the checked value to each button, which is the state of sortBy passed as props from the parent component and a “===” of the state you want it to have when the radio button is checked:
3. Set up the onChange to take the change event and call a handleSort function passed as props from the parent (both buttons will have the same handleSort function passed in):
NOTE: I used onChange because I did not want the event to be triggered when turning a button on or off, but only when the user clicked on one or the other.
4. First thing to do in the handleSort function is set the state of sortBy to the event target’s value (which in this case is ”Alphabetically”):
At this point, the radio buttons will show checked when you click on them because they are now being given a checked value:
5. Now, I would like to expand on my function and say something along the lines of “if the value is “Alphabetically” , then sort the things alphabetically, and if the value is “Price”, then sort the things by price” — BUT doing this right after setting state doesn’t work like you think it would. Instead, let’s test it by putting console.log(this.state.sortBy) so I can test that the state was set properly before moving on:
I click the Alphabetically radio button and…Oops! The console.log instead returns this:
It is logging the state of sortBy as “None”, which is still the initial state, so that means that at this point, the state of sortBy has not updated to “Alphabetically” like I expect. Now, I click the Price radio button and the console.log shows:
Now, every time I click between the radio buttons, the console.log logs the opposite value…So Alphabetically comes up when I click the price button and vice versa.
6. setState is asynchronous meaning it’s called after the completion of the function that it was called in. Since setState does not happen immediately, anything else we do IN that handleSort function will happen before setState is called. The solution to this is to pass a callback function in the setState function as the second argument to run after the state has been changed. See below — now I have a callback function to console.log the state of sortBy and it all works as expected:
Now I click on the Alphabetically button, then the price button, then Alphabetically again, and the console.log returns:
Just to review, the code I thought would work(on the left), versus the code that I needed to make it work like I expected(on the right):
React is super cool, and very functional, but it has a few things to be aware of, one of which is the fact that setState is asynchronous. So if you want to setState and then do something else immediately after, you’ll need a callback function as the second argument in your setState function to accomplish this.