带有 OnChange 的输入标签有时不起作用,反应

Input tag with OnChange sometimes doesn't work, in react

我有一个在 React 组件中呈现的函数。

该函数仅在props.teethData.data[1]["PDI"]为真时出现。我还有两个输入标签(一个是 number 类型,一个是 range 类型)它们都随着函数 sliderValueonChange 事件而改变。它似乎是随机的,但有时 setSliderP(value) 不起作用并且不会更改输入标签中的 value={sliderP}

这是一个牙齿应用程序,所以当你换牙时 teethData.data 也会改变。它往往主要发生在道具teethData.data从一颗牙齿换成另一颗牙齿然后又变回原来的牙齿时

下面是我的代码

      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>
            </>
          )
        }
      }

有人知道为什么会这样吗?

这是完整的代码,它相当大。

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;

所以我认为这里最大的问题是函数内部有 var [sliderP, setSliderP] = useState(number)

当 React re-renders 您的组件频繁时,它们将重新触发 Pdindex() 函数。因为您已将状态放入该函数中,所以您实际上丢失了状态并且 setSliderP/sliderP 将不起作用。

状态仅存储在实际组件的渲染之间。 Pdindex 不是一个组件,只是一个 returns 东西的函数。它对“useState”的使用在下一次重新渲染后消失了。

您有 2 个选择:

1.使 PdIndex() 成为一个实际的组件,以便它自己的状态在渲染之间保持不变 使 Pdindex 成为具有必要道具的功能组件,并将其用作 <Pdindex ... />

2。 (更简单,但我仍然推荐上面的方法)将 [sliderP, setSliderP] = useState(number) 移到函数 之外。所有状态都应该在 React 组件本身的顶层定义,而不是在子函数中。