1
setRadio= (id) => {
  const {formRating} = this.state;
  fetch(`http://localhost:3030/getLessonCondsDB?formId=${id}`)
  .then(response => response.json())
  .then(response=>{
                  this.setState({formRating:response.data})
                  console.log(response.data);})
  .catch(err=>console.error(err))

}

The above method assigns the JSON object which is displayed in console as [RowDataPacket {condId: 'C2.1(a)', rate: 3, condition: 'Random text here' }, RowDataPacket {condId: 'C2.2(b)',rate: 3,condition: 'more random text' }]to the state object formRating which is displayed in dev tools as below

formRating: Array
  > 0: Object
     condId: 'C2.1(a)'
     rate: '3',
     condition: 'Random text here'
  > 1: Object
     condId: 'C2.2(b)'
     rate: '3',
     condition: 'more random text'

Any attempt to console.log(formRating) just prints and empty line on the console.

Instead of fetching from the server I had previously hardcoded this data into an array as below

const formValues= [{condId :'C2.1(a)',rate:'3', condition:'Random text here'},{condId :'C2.2(b)',rate:'3', condition:'more random text'}]

and had a method in another component to create radioGroups mapping each set of conditions allowing users to change the rate value as discussed in How to set defaultValue of a radioGroup from a nested Array object in React state? which works with the hardcoded array but not the JSON array which produces a "TypeError: values.formRating.map is not a function" with the below function in the component where radioGroups are displayed allowing the user to customise the "rate" value.

createRadioGroups = ()=>{
    const {values} = this.props;
    console.log(values.formRating);
    return(values.formRating.map(
      item =>
      <Grid container>
            <Grid item xs={2} style={{marginTop:20, marginRight:0}}>{item.condId} </Grid>

            <Grid item xs={6} style={{marginTop:20}}>{item.condition} </Grid>
              <Grid item xs={4} style={{marginTop:10}}>
                <RadioGroup defaultValue={item.rate} name={item.condId}  onChange={this.changeButton(item.condId)} style={{display: 'flex', flexDirection: 'row'}}>
                  <FormControlLabel value="3" control={<Radio color="primary" />} label=' ' labelPlacement="top"/>
                  <FormControlLabel value="2" control={<Radio color="primary" />}label=' ' labelPlacement="top"/>
                  <FormControlLabel value="1" control={<Radio color="primary" />}label=' ' labelPlacement="top"/>
                  <FormControlLabel value="N/A" control={<Radio color="primary" />}label=' ' labelPlacement="top"/>
                </RadioGroup>
              </Grid>

          </Grid>

    ))
  };

Any help is appreciated.

3 Answers 3

4

That is because the fetch operation within setRadio() is asynchronous, thus any operations that are dependent on the state, or the values from setRadio() will fail. This is why calling createRadioGroups() before setRadio() is returned and completed will result in an undefined value.

I am not sure how exactly is your component structured, but you should handle any subsequent operations within the .then() block,

setRadio= (id) => {
  const {formRating} = this.state;
  fetch(`http://localhost:3030/getLessonCondsDB?formId=${id}`)
  .then(response => response.json())
  .then(response=>{
    this.setState({formRating:response.data})
    console.log(response.data);
    // do the rest here
  })
  .catch(err=>console.error(err))
}

Or if the rendering is handled on the template, you should conditionally call the method only after formRating is populated.

render() {

  const { formRating } = this.state;

  return <>
    { formRating && formRating.length && this.createRadioGroups() }
  </>

}

Or, if createRadioGroups() is on another child component,

render() {

  const { values } = this.props;

  return <>
    { values && values.formRating && values.formRating.length && this.createRadioGroups() }
  </>

}
Sign up to request clarification or add additional context in comments.

1 Comment

I think your answer sheds some light on to the issue. I am using a technique similar to whats displayed in youtube.com/watch?v=zT62eVxShsY
1

How are you passing the 'values' prop to the createRadioGroup? Seems like you need to pass it in (see snippet below) then try console logging the entire props object to make sure you are actually receiving it.

createRadioGroups = (props)=>{
    const {values} = this.props;

After you check that, then consider when you are calling setRadio? Are you sure the state has already been updated so that it is available when you call createRadioGroup? If it possibly hasn't been updated then you can try initializing your state with the 'shape' of your expected data so that it will render with no data, then rerender once the state is updated. Would look something like this:

this.state = {
  formValues= 
  [
    {
      condId :'',
      rate:'', 
      condition:''
    }
  ];

6 Comments

shaping the state object actually worked. but however now the 1 item mapped doesn't seem to be recognising item.rate correctly
I moved the createRadioGroups function to the parent component where the initial state is declared as well. createRadioGroups = ()=>{ const {formRating} = this.state; console.log(formRating); return(formRating.map( item => <Grid container>....
...<RadioGroup defaultValue={item.rate} name={item.condId} onChange={this.changeButton(item.condId)} style={{display: 'flex', flexDirection: 'row'}}> <FormControlLabel value={3} control={<Radio color="primary" />} label=' ' labelPlacement="top"/> </RadioGroup> </Grid>))};
dont know why it works but changed the database data type from INT to VARCHAR n now it's all processing correctly. Thanks @Lydia you are a lifesaver.
Seems like a type conversion issue. You can probably fix it with post-processing to convert 'rate' to a number: <RadioGroup defaultValue={parseInt(item.rate)} .... Another option would be to initialized it with 0 (so that is would be initialized as a number, not an empty string).
|
0

Try this

   return(
    <>
    this.props.values&&this.props.values.formRating.map()
    </>
   )

2 Comments

didnt work TypeError: this.props.values.formRating.map is not a function
@Dworo try now changing return statement.

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.