6.7 RadioGroup React State

Watch the video course

Overview

What you'll learn:

  • Comparing indexes
  • alert
  • Creating a functional radio group

Functional Radio group

Now, let’s make the radio group functional!

By adding the selected attribute to our <Radio> inside RadioGroup all our radios are selected.

function RadioGroup({ choices, ...props }) {
  return (
    <Frame background={null} {...props}>
      {choices.map(choice => (
<Radio selected key={choice}>{choice}</Radio>
))} </Frame> ) }
all radios selected

However, we don’t want everything to be selected. We only want one <Radio> to be selected at a time and the rest not with the values true and false respectively. Essentially, we want to have a changing value where ??? is.

function RadioGroup({ choices, ...props }) {
  return (
    <Frame background={null} {...props}>
      {choices.map(choice => (
<Radio selected={???} key={choice}>{choice}</Radio>
))} </Frame> ) }

Let’s decide what these question marks should be.

Comparing indexes

Since map is a function, specifically an arrow function, we can add another parameter.

Our only parameter currently in our arrow function is choice, so to add another parameter we have to insert a surrounding pair of parentheses.

function RadioGroup({ choices, ...props }) {
  return (
    <Frame background={null} {...props}>
{choices.map((choice, index) => (
<Radio selected={???} key={choice}>{choice}</Radio> ))} </Frame> ) }

We are going to use index to store the index of each element in the choices array. If we print out index, we’ll see 0, 1, 2 correspond with element 1, 2, 3 and so on.

Our solution involves comparing the selected index to the choices element index. Therefore, we need to define a new variable: selectedIndex.

function RadioGroup({ choices, ...props }) {
let selectedIndex = 2
return ( <Frame background={null} {...props}> {choices.map((choice, index) => (
<Radio selected={index===selectedIndex} key={choice}>{choice}</Radio>
))} </Frame> ) }

We are comparing the choices index to selectedIndex in a boolean comparison that will give us a true or false. Take note that each <Radio> has its own individual onClick function and index. Therefore, when we click on a certain Radio, we can compare its index to our selectedIndex.

Keep in mind, in JavaScript, if we want to test if two things are equal, we use three equal signs.

Since our selectedIndex = 2, the third radio is selected by array conventions.

radio 3 selected

onClick

Now, all we need to do is change the value of selectedIndex when a Radio is clicked.

Let's add onClick to our <Radio> tag. To test if onClick is being called, we can use the alert function which will show a popup dialog, similar to the functionality of console.log.

<Frame background={null} {...props}>
  {choices.map((choice, index) => (
    <Radio
      selected={index===selectedIndex}
      key={choice}
      onClick={function() {
        // change selectedIndex
        alert("clicked)
      }}>
      {choice}
    </Radio>
))}
</Frame>

However, we don’t see a dialog. This means onClick does not work yet.

Why?

Because our Radio component doesn’t know about onClick yet! For onClick to be functional, we need to set it on one of the Frames.

Spread operator

What can we use to add all the properties of <Radio> to our <Frame>?

The spread operator!

function Radio(props) {
  return (
    <Frame
      position="relative"
      size="auto"
      style={{ display: "flex", marginBottom: 10 }}
      background="null"
      {...props}
    >
    ...
  )
}
alert

If we remove the alert now and try to change selectedIndex like this will it work?

<Frame background={null} {...props}>
  {choices.map((choice, index) => (
    <Radio
      selected={index===selectedIndex}
      key={choice}
      onClick={function() {
        // change selectedIndex
        selectedIndex = 5
      }}>
      {choice}
    </Radio>
))}
</Frame>

It doesn’t!

React states

Remember, React components are like printers!

react doodle

We cannot simply change a snapshot if it’s already printed. We have to print a new page.

Our first snapshot looks similar to this:

snapshot 1

If we want to change what is shown in our preview, we have to print out a new page:

snapshot 2

useState

We can utilize useState to print a new page.

function RadioGroup({ choices, ...props }) {
let [selectedIndex, setSelectedIndex] = React.useState(0)
return( ... ) }

To change selectedIndex in our onClick function, we just have to call setSelectedIndex.

<Frame background={null} {...props}>
  {choices.map((choice, index) => (
    <Radio
      selected={index===selectedIndex}
      key={choice}
      onClick={function() {
        // change selectedIndex
        setSelectedIndex(index)
      }}>
      {choice}
    </Radio>
))}
</Frame>
final result

We now have a fully functional radio group that we built from scratch!

Conclusion

The radio group module is finished! Along the way we learned how to create a counter and about React snapshots, React States, useState, rendering, coding tips, code efficiency, the spread operator, and more!

In the next post, we'll go back to our toggle and truly understand what useCycle is.