Home > Software design >  Input tag with OnChange sometimes doesn't work, in react
Input tag with OnChange sometimes doesn't work, in react

Time:05-10

I have a function that renders in a component in react.

The function only appears when props.teethData.data[1]["PDI"] is true. I also have two input tags (one is type number, one is type range) they both change with the function sliderValue with an onChange event. it seems to be at random but sometimes the setSliderP(value) does not work and does not change the value={sliderP} in the input tags.

This is for a Teeth app, so when you change tooth teethData.data also changes. It tends to mostly happen when the props.teethData.data changes from one tooth to another and then back to the original tooth

Heres my code below

      function Pdindex()  {
        let number = 1
        if (props.teethData.data[1]["PDI"]) {  //Checks to see if ticked true 
          if (props.teethData.data[1]["PDI"][1] === undefined) { //if undefined -> because this first time setting value
            props.teethData.data[1]["PDI"] = [true, number] //make sure props are update
          } else {
            console.log('happened', props.teethData.data[1]["PDI"][1] ) //The value has been set before
            number = props.teethData.data[1]["PDI"][1] 
          }
        } else {
          console.log('this should happen when props.teethData.data[1]["PDI"] is not true')
        }
        var [sliderP, setSliderP] = useState(number)
        sliderP = number //for some reason it needs me to do this as useState(number) doesnt work
        function sliderValue(value) {
          sliderP = value
          props.teethData.data[1]["PDI"] = [true, value]
          setSliderP(value)
        }
        if (props.teethData.data[1]["PDI"]) {
          return (
            <>
              <div>
                <div className="spacing-30">
                  <input onChange={(event)=>sliderValue(event.target.value)} type='range' min="0" max="4" value={sliderP}/> 
                  <input type='number' min="0" max="4" className="slider-number" onChange={(event)=>sliderValue(event.target.value)} value={sliderP}/>
                </div>
              </div>
            </>
          )
        }
      }

Does anyone know why this could be?

Heres the full code, its quite large.

import PeriodPopUp from "../tooltips/periodPocketDepth";
import C14PopUp from "../tooltips/calculusIndex";
import GI03PopUp from "../tooltips/gingiv";
import GR14PopUp from "../tooltips/gingivRecession";
import PDIPopUp from "../tooltips/PDI";
import M03PopUp from "../tooltips/mobility";
import { useState, useEffect, useRef } from "react";


function PeriodontalDisplay(props) {

  console.log(props, 'period tooooooth table')



    const [PPDtrigger, SetPPDtrigger] = useState(false)
    function PPDtriggerPop(){
      SetPPDtrigger(!PPDtrigger) 
    }
  
    const [C14trigger, SetC14trigger] = useState(false)
    function C14triggerPop(){
      SetC14trigger(!C14trigger) 
    }
  
    const [GI03trigger, SetGI03trigger] = useState(false)
    function GI03triggerPop(){
      SetGI03trigger(!GI03trigger) 
    }
  
    const [GR14trigger, SetGR14trigger] = useState(false)
    function GR14triggerPop(){
      SetGR14trigger(!GR14trigger) 
    }
    const [PDItrigger, SetPDItrigger] = useState(false)
    function PDItriggerPop(){
      SetPDItrigger(!PDItrigger) 
    }
  
    const [M03trigger, SetM03trigger] = useState(false)
    function M03triggerPop(){
      SetM03trigger(!M03trigger) 
    }

    function Periodontalpocketdepth()  {


      
      let ppArray = {}
      if (props.teethData.data[1]["PP"].length > 1) {
        //console.log(props.teethData.data[1]["PP"], 'pp here values lets see')
        ppArray = {
          'aValue':props.teethData.data[1]["PP"][1]['aValue'],
          'bValue':props.teethData.data[1]["PP"][1]['bValue'],
          'cValue':props.teethData.data[1]["PP"][1]['cValue'],
          'dValue':props.teethData.data[1]["PP"][1]['dValue'],
          'eValue':props.teethData.data[1]["PP"][1]['eValue'],
          'fValue':props.teethData.data[1]["PP"][1]['fValue']
        }


      } else {
        //console.log('pp arent here',props.teethData.data)
        ppArray = {
          'aValue':0,
          'bValue':0,
          'cValue':0,
          'dValue':0,
          'eValue':0,
          'fValue':0
        }
        

      }

      const [aValue, setValue] = useState(ppArray)



      function sliderValue(value, type) {
        //console.log('call', value, type)
        if(type === 'aValue') {
          setValue((prevState) => {
            return { ...prevState, aValue: value };
          });
          props.teethData.data[1]["PP"] = [true, aValue]

        } else if (type === 'bValue') {
          setValue((prevState) => {
            return { ...prevState, bValue: value };
          });
          props.teethData.data[1]["PP"] = [true, aValue]

        } else if (type === 'cValue') {
          setValue((prevState) => {
            return { ...prevState, cValue: value };
          });
          props.teethData.data[1]["PP"] = [true, aValue]

        } else if (type === 'dValue') {
          setValue((prevState) => {
            return { ...prevState, dValue: value };
          });
          props.teethData.data[1]["PP"] = [true, aValue]

        } else if (type === 'eValue') {
          setValue((prevState) => {
            return { ...prevState, eValue: value };
          });
          props.teethData.data[1]["PP"] = [true, aValue]

        } else if (type === 'fValue') {
          setValue((prevState) => {
            return { ...prevState, fValue: value };
          });
          props.teethData.data[1]["PP"] = [true, aValue]
        } 

      }



      if (props.teethData.data[1]["PP"]) {
        return (
          <>
            <div>
              <div className="spacing-30">
                  <input type='number' className="input-pp" min="0" max="10" onChange={(event)=>sliderValue(event.target.value, 'aValue')} value={aValue.aValue}/>
                  <label className="label-white">A (Mesio-buccal)</label>
              </div>
              <div className="spacing-30">
                <input type='number' className="input-pp" min="0" max="10" onChange={(event)=>sliderValue(event.target.value, 'bValue')} value={aValue.bValue}/>
                <label className="label-white">B (Mesio-buccal)</label>
              </div>
              <div className="spacing-30">
                <input type='number' className="input-pp" min="0" max="10" onChange={(event)=>sliderValue(event.target.value, 'cValue')} value={aValue.cValue}/>
                <label className="label-white">C (Mesio-buccal)</label>
              </div>
            </div>
            <div>
              <div className="spacing-30">
                <input type='number' className="input-pp" min="0" max="10" onChange={(event)=>sliderValue(event.target.value, 'dValue')} value={aValue.dValue}/>
                <label className="label-white">D (Mesio-palatal/lingual)</label>
              </div>
              <div className="spacing-30">
                <input type='number' className="input-pp" min="0" max="10" onChange={(event)=>sliderValue(event.target.value, 'eValue')} value={aValue.eValue}/>
                <label className="label-white">E (Palatal/lingual)</label>
              </div>
              <div className="spacing-30">
                <input type='number' className="input-pp" min="0" max="10" onChange={(event)=>sliderValue(event.target.value, 'fValue')} value={aValue.fValue}/>
                <label className="label-white">F (Disto-palatal/lingual)</label>
              </div>
            </div>
  
          </>
        )
      }
      }

      function CalculusIndex()  {
        let number = 0
        if (props.teethData.data[1]["C14"].length>1) {
          number = props.teethData.data[1]["C14"][1]
        } else {
          number = 0
        }
        const [slider, setSlider] = useState(number)
        
        function sliderValue(value) {
          props.teethData.data[1]["C14"] = [true, value]
          setSlider(value)

        }
        if (props.teethData.data[1]["C14"]) {
          return (
            <>
              <div>
                <div className="spacing-30">
                  
                  <input onChange={(event)=>sliderValue(event.target.value)} type='range' min="1" max="4" value={slider}/> 
                  <input type='number' className="slider-number" onChange={(event)=>sliderValue(event.target.value)} value={slider}/>

                  </div>
              </div>
            </>
          )
        }
      }

      function GingIndex()  {
        let number = 0
        if (props.teethData.data[1]["GI0"]) {  //Checks to see if ticked true
          if (props.teethData.data[1]["GI0"][1] === undefined) { //if undefined -> because this first time setting value
            props.teethData.data[1]["GI0"] = [true, number] //make sure props are update
          } else {
            number = props.teethData.data[1]["GI0"][1] 
          }
        } 
        var [slider, setSlider] = useState(number)
        slider = number
        function sliderValue(value) {
          slider = value
          props.teethData.data[1]["GI0"] = [true, value]
          setSlider(value)
        }

        if (props.teethData.data[1]["GI0"]) {
          return (
            <>
              <div>
                <div className="spacing-30">
                  <input onChange={(event)=>sliderValue(event.target.value)} type='range' min="0" max="3" value={slider}/> 
                  <input type='number' min="0" max="3" className="slider-number" onChange={(event)=>sliderValue(event.target.value)} value={slider}/>
                </div>
              </div>
            </>
          )
        }
      }

      function GingRecess()  {
        let number = 0
        if (props.teethData.data[1]["GR"]) {  //Checks to see if ticked true
          if (props.teethData.data[1]["GR"][1] === undefined) { //if undefined -> because this first time setting value
            number = 1
            props.teethData.data[1]["GR"] = [true, number] //make sure props are update
          } else {
            number = props.teethData.data[1]["GR"][1] 
          }
        } 
        var [slider, setSlider] = useState(number)
        slider = number
        
        function sliderValue(value) {
          props.teethData.data[1]["GR"] = [true, value]
          setSlider(value)
        }
        if (props.teethData.data[1]["GR"]) {
          return (
            <>
              <div>
                <div className="spacing-30">
                  <input onChange={(event)=>sliderValue(event.target.value)} type='range' min="1" max="4" value={slider}/> 
                  <input type='number' className="slider-number" onChange={(event)=>sliderValue(event.target.value)} value={slider}/>
                </div>
              </div>
            </>
          )
        }
      }

      function Pdindex()  {
        let number = 1
        if (props.teethData.data[1]["PDI"]) {  //Checks to see if ticked true 
          if (props.teethData.data[1]["PDI"][1] === undefined) { //if undefined -> because this first time setting value
            props.teethData.data[1]["PDI"] = [true, number] //make sure props are update
          } else {
            console.log('happened', props.teethData.data[1]["PDI"][1] ) //The value has been set before
            number = props.teethData.data[1]["PDI"][1] 
          }
        } else {
          console.log('this should happen when props.teethData.data[1]["PDI"] is not true')
        }
        var [sliderP, setSliderP] = useState(number)
        sliderP = number //for some reason it needs me to do this as useState(number) doesnt work
        function sliderValue(value) {
          sliderP = value
          props.teethData.data[1]["PDI"] = [true, value]
          setSliderP(value)
        }
        if (props.teethData.data[1]["PDI"]) {
          return (
            <>
              <div>
                <div className="spacing-30">
                  <input onChange={(event)=>sliderValue(event.target.value)} type='range' min="0" max="4" value={sliderP}/> 
                  <input type='number' min="0" max="4" className="slider-number" onChange={(event)=>sliderValue(event.target.value)} value={sliderP}/>
                </div>
              </div>
            </>
          )
        }
      }

      function Mob()  {
        let number = 0
        if (props.teethData.data[1]["M03"].length>1) {
          number = props.teethData.data[1]["M03"][1]
        } else {
          number = 0
        }
        const [slider, setSlider] = useState(number)
        function sliderValue(value) {
          props.teethData.data[1]["M03"] = [true, value]
          setSlider(value)

        }
        if (props.teethData.data[1]["M03"]) {
          return (
            <>
              <div>
                <div className="spacing-30">
                  <input onChange={(event)=>sliderValue(event.target.value)} type='range' min="0" max="3" value={slider}/> 
                  <input type='number' className="slider-number" onChange={(event)=>sliderValue(event.target.value)} value={slider}/>
                </div>
              </div>
            </>
          )
        }
      }






    return (
      <div className="period-table">

        <div className="period-table-sec">

          <input
            className="check-box"
            type="checkbox"
            id="pp"
            onChange={() => props.onToothCondition(1, "PP")}
            checked={props.teethData.data[1]["PP"]}
          />
          <label className="text-check-box" id="PP">
            <dt>PP #</dt> Periodontal pocket depth <button className="questionButton"  onClick={() => SetPPDtrigger(!PPDtrigger)}> ?  </button>
            
            <PeriodPopUp trigger={PPDtrigger}  onTrigger={PPDtriggerPop} animalType={props.animalType}> </PeriodPopUp>
          </label>
          <div className="right-table">
            {Periodontalpocketdepth()}
          </div>    
        </div>


        <div className="wrapper-table">

          <div className="first-table">
            <input
              className="check-box"
              type="checkbox"
              id="C14"
              checked={props.teethData.data[1]["C14"]}
              onChange={() => props.onToothCondition(1, "C14")}
            />
            <label className="text-check-box" id="C14">
              <dt>C 1-4</dt> calculus index <button className="questionButton" onClick={() => SetC14trigger(!C14trigger)}> ?  </button>
              <C14PopUp trigger={C14trigger}  onTrigger={C14triggerPop} animalType={props.animalType}></C14PopUp>
            </label>
            <div className="right-pp">
              {CalculusIndex()}
            </div>
          </div>




          <div className="second-table">
            <input
              className="check-box"
              type="checkbox"
              id="GI0"
              onChange={() => props.onToothCondition(1, "GI0")}
              checked={props.teethData.data[1]["GI0"]}
            />
            <label className="text-check-box" id="GI0">
              <dt>GI 0-3</dt> gingivitis index <button className="questionButton" onClick={() => SetGI03trigger(!GI03trigger)}> ?  </button>
              <GI03PopUp trigger={GI03trigger}  onTrigger={GI03triggerPop} animalType={props.animalType}></GI03PopUp>
            </label>
            <div className="right-pp">
              {GingIndex()}
            </div>
          </div>
        </div>

        <div className="wrapper-table">
          <div className="first-table">
            <input
              className="check-box"
              type="checkbox"
              id="GI23"
              onChange={() => props.onToothCondition(1, "GI23")}
              checked={props.teethData.data[1]["GI23"]}
            />
            <label className="text-check-box" id="GI">
              <dt> GI 2/3</dt> Bleeding when probing 
            </label>
          </div>
          <div className="second-table">
            <input
              className="check-box"
              type="checkbox"
              id="GR"
              onChange={() => props.onToothCondition(1, "GR")}
              checked={props.teethData.data[1]["GR"]}
            />
            <label className="text-check-box" id="GR">
              <dt>GR 1-4</dt> gingival recession <button className="questionButton" onClick={() => SetGR14trigger(!GR14trigger)}> ?  </button>
              <GR14PopUp trigger={GR14trigger}  onTrigger={GR14triggerPop} animalType={props.animalType}></GR14PopUp>
            </label>
            <div className="right-pp">
              {GingRecess()}
            </div>
          </div>
        </div>

        <div className="wrapper-table">
          <div className="first-table">
            <input
              className="check-box"
              type="checkbox"
              id="PDI"
              onChange={() => props.onToothCondition(1, "PDI")}
              checked={props.teethData.data[1]["PDI"]}
            />
            <label className="text-check-box" id="PDI">
              <dt>PDI/ 0-4 </dt>periodontal disease index  <button className="questionButton" onClick={() => SetPDItrigger(!PDItrigger)}> ?  </button>
              <PDIPopUp trigger={PDItrigger}  onTrigger={PDItriggerPop} animalType={props.animalType}></PDIPopUp>
              

            </label>
            <div className="right-pp">
              {Pdindex()}
            </div>
          </div>
          <div className="second-table">
            <input
              className="check-box"
              type="checkbox"
              id="M03"
              onChange={() => props.onToothCondition(1, "M03")}
              checked={props.teethData.data[1]["M03"]}
            />
            <label className="text-check-box" id="M03">
              <dt>M 0-3</dt> mobility  <button className="questionButton"  onClick={() => SetM03trigger(!M03trigger)}> ?  </button>
              <M03PopUp trigger={M03trigger}  onTrigger={M03triggerPop} animalType={props.animalType}> </M03PopUp>
            </label>
            <div className="right-pp">
              {Mob()}
            </div>
          </div>
        </div>

        <div className="wrapper-table">
          <div className="first-table">
            <input
              className="check-box"
              type="checkbox"
              id="furcation"
              onChange={() => props.onToothCondition(1, "F13")}
              checked={props.teethData.data[1]["F13"]}
            />
            <label className="text-check-box" id="furcation">
              <dt> F 1-3 </dt>furcation <button className="questionButton"> ?  </button>
            </label>
          </div>
        </div>
      </div>
    );
  }

  export default PeriodontalDisplay;

CodePudding user response:

So I think the biggest issue here is having var [sliderP, setSliderP] = useState(number) inside the function.

When React re-renders your component frequently, they're going to retrigger the Pdindex() function. Because you've put the state inside that function, you actually lose state and the setSliderP/sliderP won't work.

The state is only stored between renders for actual components. Pdindex is not a component, just a function that returns something. Its usage of "useState" is gone after the next rerender.

You have 2 options:

1. Make PdIndex() an actual component so that its own state persists between renders Make Pdindex a functional component with the necessary props and use it as <Pdindex ... />

2. (simpler but I'd recommend the above still) Move the [sliderP, setSliderP] = useState(number) outside of the function. All state should be defined toplevel within the react component itself, not within subfunctions.

  • Related