1

I have a state in react called options that looks like:

{
  "0": ["Peru", "Brazil", "Colombia", "Ecuador"],
  "1": ["False", "True"],
  "2": ["Kurdish", "Arab", "Egyptian", "Syrian"],
  "3": ["True", "False"],
  "4": ["Just Cause 2", "Grand Theft Auto 5", "The Elder Scrolls 4:  Oblivion", "The Witcher 3:  Wild Hunt"]
}

I want the array values to render in a radio group, In this example RadioGroup 1 should contain radio buttons of object key "0", RadioGroup 2 of object key "1" and so on...

For a more visual example:

//Radio Group 1
O Peru
O Brazil
O Columbia
O Ecuador

//Radio Group 2
O False
O True

I am trying to do like this but the Radio isn't rendering in Object.values, I have tested it does render outside of Object.values if I put some constant value (for testing purpose)

const renderAnswers = (index) => {  // don't worry about what index is, just remember that I'm calling this function in main render
    return (
        <RadioGroup aria-label="quiz" name="quiz" onChange={handleRadioChange(index)}>
            {
                // Works but not inside Object.values
                // <FormControlLabel value="F" control={<Radio color="primary" />} label="F"} />
                Object.values(options).map((val, key) => {  //options is the state that I was talking about in the beginning                
                    val.map((v, k) => {
                        return (    
                            // Doesn't work I don't know why?
                            <FormControlLabel value={decodeEntities(v)} control={<Radio color="primary" />} label={decodeEntities(v)} />
                        );
                    })
                })
            }
        </RadioGroup>
    );
}

SideNote: because my array can contain special characters decodeEntities is a function that decodes special characters and codes and returns the string

Drew Reese solution does this:

//Radio Group 1
O Peru
O Brazil
O Columbia
O Ecuador
O False
O True
O Kurdish
O Arab
O Egyption
O Syrian
O True
O False
O Just 2 Cause
O Grand Theft Auto 5
O The Elder Scrolls 4: Oblivion
O The Witcher 3: Wild Hunt

and same for all the other radio groups

In the main render I'm doing something like

props.data.results.map((val, index) => {
    return (
        <Grid item xs={12}>
            <Card>
                <CardContent>
                    <Grid container spacing={6} direction="column" justify="center" alignItems="center">
                        <Grid item xs={12}>
                            <Typography
                            variant="h6"
                            component="h6">
                            {decodeEntities(val.question)}
                            </Typography>
                        </Grid>
                        <Grid item xs={12}>
                            {renderAnswers(index)} // notice
                        </Grid>
                    </Grid>
                </CardContent>
            </Card>
        </Grid>
    );
}

in this case data is passed as a prop through another component if you wanna more : https://github.com/JunedKhan101/Quiz-game the file you are looking for is src > Components > QuizForm.js

1 Answer 1

2

Issue

It doesn't seem you are returning the outer elements being mapped.

Object.values(options).map((val, key) => {    
  val.map((v, k) => { // <-- not returned !!
    return (    
      <FormControlLabel
        value={decodeEntities(v)}
        control={<Radio color="primary" />}
        label={decodeEntities(v)}
      />
    );
  })
})

Solution

Return what you are mapping.

Object.values(options).map((val, key) => {    
  return val.map((v, k) => {
    return (    
      <FormControlLabel
        value={decodeEntities(v)}
        control={<Radio color="primary" />}
        label={decodeEntities(v)}
      />
    );
  })
})

Or remove the curly brackets and use implicit returns

Object.values(options).map((val, key) =>
  val.map((v, k) => (
    <FormControlLabel
      value={decodeEntities(v)}
      control={<Radio color="primary" />}
      label={decodeEntities(v)}
    />
  ))
)

Edit 1

This, of course, renders all the options into the one single RadioGroup component.

If you want separate radio groups for each nested array of options you will need to first map multiple RadioGroup components, then map the options.

const renderAnswers = (index) => {
  return Object.values(options).map((group, groupIndex) => (
    <RadioGroup
      key={groupIndex}
      aria-label="quiz"
      name="quiz"
      onChange={handleRadioChange(index)}
    >
      {group.map((option, optionIndex) => {
        return (
          <FormControlLabel
            key={optionIndex}
            value={decodeEntities(option)}
            control={<Radio color="primary" />}
            label={decodeEntities(option)}
          />
        );
      })}
    </RadioGroup>
  ));
};

Note

You should note that the reason it appears as one single radio group is because you've no additional UI to help "group" the radio groups visually, i.e. no labels or dividers between them.

Edit 2

After discussion I believe you intended to use the passed index and access a specific array to render into a radio group.

const renderAnswers = (index) => {
  return (
    <RadioGroup
      aria-label="quiz"
      name="quiz"
      onChange={handleRadioChange(index)}
    >
      {options[index].map((option, index) => (
        <FormControlLabel
          key={index}
          value={decodeEntities(option)}
          control={<Radio color="primary" />}
          label={decodeEntities(option)}
        />
      ))}
    </RadioGroup>
  );
};
Sign up to request clarification or add additional context in comments.

7 Comments

I tried the solution you mentioned but every Radio Group is containing all array elements from the object which is not what I want read my question again
@Emilia-tan I read your question clearly. You've only giant radio group with the way you've mapped them. Are you saying to want a separate radio group for each nested array of options?
Yes, Radio Group one should contain array elements from options key "0" and Radio group 2 should contain from options key "1" and so on...
@Emilia-tan I added to my solution. Please review it and see if it now works for your desired use-case. Though I am curious about what you say your options state shape actually is. Is it really an object (with array index-like keys)? Also, what is the index argument that is passed used for?
The result is the same as before it's rendering all the array elements from options to all the Radio groups I think at this point I should give you more info I'm making a quiz game, I'm fetching the data from an API, data.results is an array of objects that contains what I want data.results[index].question has the question (index represents the number less than the amount of results fetched) For example If I am fetching 10 question from API then index < 10, I'm looping through data.results.map() to render all the question and answers (options)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.