Home > Software design >  React component is not rendering after state change with button click while using useContext hook
React component is not rendering after state change with button click while using useContext hook

Time:10-26

I am using useContext hook for the first time as I wanted the re-rendering of one component by click of a button component. Here's my code:

QuestionContext.js (for creating context):

import { createContext } from "react";

const QuestionContext = createContext()

export default QuestionContext

SectionState.js (for providing value to children):

import {React, useState} from 'react'
import QuestionContext from './QuestionContext'
import questions from '../data/questions.json'


const SectionState = (props) => {
  
  // set questions from json to an array of 4 elements
  const newQuestions = Object.keys(questions.content).map(key => questions.content[key].question)
  
  const newState = {
    "qID": 0,
    "questionTxt": newQuestions[0],
  }
  
  //useState for Question state
  const [currentQuestion, setCurrentQuestion] = useState(0)
  const [questionCtx, setQuestionCtx] = useState(newState)
  
  const updateQuestion = () => {
    if(currentQuestion > newQuestions.length) {
      console.log("no more questions")
    }
    else{
      setCurrentQuestion(currentQuestion   1)
      setQuestionCtx(() => ({
        "qID": currentQuestion,
        "questionTxt": newQuestions[currentQuestion]
      }))
    }
  } 
  
  return (
    <QuestionContext.Provider value = {{newState, updateQuestion}}>
      {props.children}
    </QuestionContext.Provider>
  )
}

export default SectionState

The following two components are child of <SectionState /> component

Buttons.js:

import React, { useContext } from 'react'
import QuestionContext from '../context/QuestionContext'

const Buttons = () => {
  
    const example = useContext(QuestionContext)
    
    const clickHandler = () => {
        example.updateQuestion()
    }
  
    return (
    <div className='flex flex-row justify-between'>
        {/* <button className='btn backdrop-blur-md bg-slate-600 rounded-full xl:w-48 md:w-44 text-slate-50' onClick={ clickHandler }>Prev</button> */}
        <button className='btn btn-accent rounded-full xl:w-48 md:w-44' onClick={ clickHandler }>Next</button>
    </div>
  )
}

export default Buttons

Questions.js

import { React, useContext } from 'react'
import './styles/Questions.css'
import QuestionContext from '../context/QuestionContext'

const Questions = () => {

  const newContext = useContext(QuestionContext)
  return (
    <>
      <h1 className='text-4xl text-zinc-50'>{ newContext.newState.questionTxt }</h1>
    </>
  )
}

export default Questions

Every time I have clicked on the button, I could check in the console that newState state has changed, but this new state won't render in <Questions /> component. I could still see newContext.newState.questionTxt holding the initial value i.e. newQuestions[0]. What am I doing wrong here?

Here's a reproduced link in code sandbox

CodePudding user response:

<QuestionContext.Provider value = {{newState, updateQuestion}}

Here you passed newState and updateQuestion as a value of context. In Button component you update currentQuestion and questionCtx using updateQuestion() but in Questions component, you are using the value of newState as

const newContext = useContext(QuestionContext)
<h1 className='text-4xl text-zinc-50'>{ newContext.newState.questionTxt }</h1>

Here newState is not a state. It is just a variable and it is not updated at all so you don't get an updated value in Question component.

Solution: So I think you should pass the questionCtx as a value of context Provider like

<QuestionContext.Provider value = {{questionCtx , updateQuestion}}

Use it like

<h1 className='text-4xl text-zinc-50'>{ newContext.questionCtx.questionTxt }</h1>

Working Codesandbox link: https://codesandbox.io/s/react-usecontext-forked-frgtw1?file=/src/context/SectionState.js

  • Related