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.