TransWikia.com

React returning view from switch statement

Stack Overflow Asked by MattBlack on November 10, 2021

I am using a switch to return a view depending on the ‘question type’ in an array.

A ‘next’ button will trigger the next question by moving once along the array.

const questionSwitcher = (question) => {
     
    switch(question.question_type) {
      case 1:
        return <Type1Question data={question} resultBanner={(data) => setResultBanner(data)}/>;
        case 2:
        return <Type2Question data={question} resultBanner={(data) => setResultBanner(data)}/>;
      default:
        return <div>Error</div>
    }
  }

The issue I have is that inside of the returned views I have a text area, if the same view is returned successively the content within the text area remains the text from the previous question.

I suspect that because it is returning the same view its not re-rendering the component but simply replacing the data within it.

How would I force the view to be reloaded if the same view is returned?

export default function Course(props) {

  const history = useHistory();

  const [resultBanner, setResultBanner] = useState(false);
  const [currentQuestion, setCurrentQuestion] = useState(0);
  const [questionVisible, setQuestionVisible] = useState(true);

  const nextQuestion = () => {
    setResultBanner(false);
    setCurrentQuestion(currentQuestion + 1);
  }

  const handleClose = () => {
      history.push("/viewcourse")
  }

  const courseData = {
    "id": 1,
    "course_title": "",
    "course_description": "",
    "course_image": "",
    "course_completions": 0,
    "course_rating": 4.8,
    "sections": [{
      "id": 1,
      "title": "",
      "oreder_random": true,
      "questions": [{
        "id": 1,
        "question_type":1,
        "prompt_text": "Translate the following",
        "question_text": "O menino",
        "audio_file": "",
        "accepted_answers": ["The boy"]
      },{
        "id": 2,
        "question_type":2,
        "prompt_text": "Translate the following",
        "question_text": "O homem",
        "audio_file": "",
        "accepted_answers": ["The man"]
      }]
    }]
  }

  const questionSwitcher = (question) => {
     
    switch(question.question_type) {
      case 1:
        return <Type1Question data={question} resultBanner={(data) => setResultBanner(data)}/>;
        case 2:
        return <Type2Question data={question} resultBanner={(data) => setResultBanner(data)}/>;
      default:
        return <div>Error</div>
    }
  }

  return (

    <div>

  <div style={{height:'100%',position: 'absolute', width:'100%', zIndex:1}}>
  <Container fluid="md" style={{height:'100%', width:'100%'}}>
  <Row style={{height:'10%',display: 'flex',alignItems: 'center'}}><Col xs={10}><ProgressBar striped variant="warning" now={11} /></Col><Col xs={2} style={{display: 'flex',justifyContent: 'flex-end'}}><img src={CloseButton} alt="close button" style={{width:'15px', height:'15px'}} onClick={() => handleClose()}/></Col></Row>
  <Row style={{height:'90%'}}><Col xs={12}>{questionSwitcher(courseData.sections[0].questions[currentQuestion])}</Col></Row>
  </Container>
  </div>
    
    {resultBanner &&
    <div style={{height:'30%',maxHeight:'200px',position: 'absolute', width:'100%', bottom:'0px', zIndex:2}}>
    <Container style={{height:'100%', width:'100%', padding:0, overflow:'hidden'}} fluid>
    <Row style={{height:'100%'}} ><Col xs={12}><ResultBanner data={resultBanner} nextQuestion={() => nextQuestion()}/></Col></Row>
    </Container>
    </div>
}
    </div>
  );
}

QuestionView:

export default function Type1(props) {

  const [answerText, setAnswerText] = useState("");

const checkAnswer = () => {

  var isCorrect = false;

  for (const [index, value] of props.data.accepted_answers.entries()) {
    console.log(value);

    if(answerText.toLowerCase().normalize("NFD").replace(/[u0300-u036f]/g, "") === value.toLowerCase().normalize("NFD").replace(/[u0300-u036f]/g, "")){
      isCorrect = true;
    }
  }

  if(isCorrect === true){
    props.resultBanner({isCorrect: true})
  }else{
    props.resultBanner({isCorrect: false})
  }

}

  return (

    <Container style={{height:'100%', position:'absolute', left:0}}>

<Row style={{height:'calc(100% - 50px)',overflow:'scroll'}}>

    <Container fluid="md">
   <Row ><Col>
   <Container >
    <Row style={{paddingTop:'10px'}}><Col><font style={{fontFamily:'MainFont', fontSize:'20px'}}>{props.data.prompt_text}</font></Col></Row>
    <Row style={{paddingTop:'30px'}}><Col xs={3} sm={2} md={2} lg={2} xl={2}><Image src={Boy} alt="person" style={{width:'100%'}} fluid/></Col><Col ><div style={{border: '2px solid #e5e5e5',borderRadius:'15px', display: 'inline-block', padding:'10px'}}><font style={{fontFamily:'MainFont', fontSize:'18px'}}>{props.data.question_text}</font></div></Col></Row>
    <Row style={{paddingTop:'30px'}}><Col>
    
    <Form.Control as="textarea" rows="3" onChange={(event) => setAnswerText(event.target.value)} value={answerText}/>
  
    </Col></Row>
    </Container>
   </Col></Row>
    </Container>
    </Row>

<Row style={{height:'50px',backgroundColor:'#6f61b3'}}><Button style={{width:'100%',backgroundColor:'#6f61b3', border:'none', height:'100%'}} onClick={checkAnswer}>Submit</Button></Row>

</Container>
  );
}

One Answer

Looks possibly like an issue with Reconcilliation not working as you'd first expect it to. It sees the divs being very similar, and only updates the attributes that have changed, leaving the internal elements the same.

You could add a key={1} and key={2} prop to the text input boxes within the question1 and question2 components, that way React would know to treat them as different elements.

Answered by Luke Storry on November 10, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP