简体   繁体   English

为什么我的计数器值在点击开始减少之前会增加 - reactjs

[英]Why does my counter value increase before it starts to decrease on click - reactjs

I'm making an attendance form where teachers can mark who's absent and not and check who was absent the previous days.我正在制作出勤表,教师可以在其中标记谁缺席和未缺席,并检查前几天谁缺席。 I have the current date at the top and button which allows it to change the date forward and back.我在顶部有当前日期和按钮,它允许它向前和向后更改日期。 However, when I try to increase the value it works fine, but then when I decrease it increases by one first and then decreases after every click.但是,当我尝试增加该值时,它可以正常工作,但是当我减少它时,它首先增加一,然后在每次点击后减少。

 const [date, setDate] = useState()

  var today = new Date();
    var dd = parseInt(String(today.getDate()).padStart(2, '0'));
    var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
    var yyyy = today.getFullYear(); 
    
    today = dd + '/' + mm + '/' + yyyy;
    useEffect(() => {
      setDate(today)

    }, [])

const[newDay, setNewDay] = useState(dd)
  
  const changeToTomorrow = () => {
    setNewDay(newDay + 1)
    setDate(newDay + '/' + mm + '/' + yyyy)
    console.log(date)
  }

  const changeToYesterday = () => {
    setNewDay(newDay - 1)
    setDate(newDay + '/' + mm + '/' + yyyy)
  }


    return (
        <div className="attendance-today-container">
          <h1>Daily attendance</h1>
          <div className='change-date-container'>
            <div className='change-date'>
              <i class="fas fa-arrow-left" onClick={changeToYesterday}></i>
              <p>{date}</p>
              <i class="fas fa-arrow-right" onClick={changeToTomorrow}></i>
            </div>
          </div>

When you update a state using setNewDay(newDay + 1) the newDay variable is not immediately updated.当您使用setNewDay(newDay + 1)更新 state 时,不会立即更新newDay变量。 So when you do setDate(newDay + '/' + mm + '/' + yyyy) you still use the old value of newDay to update date .因此,当您执行setDate(newDay + '/' + mm + '/' + yyyy)时,您仍然使用newDay的旧值来更新date

Example:例子:

You have initial state newDay = 10 date = 10/xx/xx , then you click on increase button and the next code is executed.您有初始 state newDay = 10 date = 10/xx/xx ,然后单击增加按钮并执行下一个代码。 setNewDay(10 + 1) setDate(10 + '/' + mm + '/' + yyyy) setNewDay(10 + 1) setDate(10 + '/' + mm + '/' + yyyy)

After react renders component with a new state you got newDay = 11 date = 10/xx/xx on the next click to increase you would get setNewDay(11 + 1) setDate(11 + '/' + mm + '/' + yyyy)在使用新的 state 渲染组件后,您在下一次单击以增加时会得到newDay = 11 date = 10/xx/xx您将得到setNewDay(11 + 1) setDate(11 + '/' + mm + '/' + yyyy)

So you date variable update is always one step behind.所以你的date变量更新总是落后一步。

How to fix怎么修

You should do something like你应该做类似的事情

let nextDay = newDay + 1
setNewDay(nextDay)
setDate(nextDay + '/' + mm + '/' + yyyy)

in both functions在这两个功能中

You are trying to set two states in a row while those are asynchronous and might not give you the updated value of newDay by the time you set date.您正在尝试连续设置两个状态,而这些状态是异步的,并且可能不会在您设置日期时为您提供 newDay 的更新值。

A fast fix can be as follows (I rearrange the code a bit with spacing):快速修复可以如下(我用间距重新排列代码):

import {useState, useEffect} from "react";

export default function SomeComponent() {
  
  const [date, setDate] = useState()

  var today = new Date();
  var dd = parseInt(String(today.getDate()).padStart(2, '0'));
  var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
  var yyyy = today.getFullYear(); 
  
  today = dd + '/' + mm + '/' + yyyy;
  useEffect(() => {
    setDate(today)

  }, [])

  const[newDay, setNewDay] = useState(dd)

  const changeToTomorrow = () => {
    const updateDay = newDay + 1
    setNewDay(updateDay)
    setDate(updateDay + '/' + mm + '/' + yyyy)
    console.log(date)
  }

  const changeToYesterday = () => {
    const updateDay = newDay - 1
    setNewDay(updateDay)
    setDate(updateDay + '/' + mm + '/' + yyyy)
  }


  return (
      <div className="attendance-today-container">
        <h1>Daily attendance</h1>
        <div className='change-date-container'>
          <div className='change-date'>
            <i class="fas fa-arrow-left" onClick={changeToYesterday}></i>
            <p>{date}</p>
            <i class="fas fa-arrow-right" onClick={changeToTomorrow}></i>
          </div>
        </div>
      </div>
  );
}

Calculate the updated date first in a new variable and then set it to both states:首先在新变量中计算更新日期,然后将其设置为两种状态:

  const changeToTomorrow = () => {
    const updateDay = newDay + 1
    setNewDay(updateDay)
    setDate(updateDay + '/' + mm + '/' + yyyy)
    console.log(date)
  }

  const changeToYesterday = () => {
    const updateDay = newDay - 1
    setNewDay(updateDay)
    setDate(updateDay + '/' + mm + '/' + yyyy)
  }

May I suggest a different approach, as well as a different organization of the code?我可以建议一种不同的方法,以及不同的代码组织吗?

 const { useState, useEffect, useCallback } = React; // utility function (not part of the component) function formatDate(date, format = 'dd/mm/yyyy') { const addLeadingZero = num => { return num < 10? `0${num}`: num.toString(); } const dd = addLeadingZero(date.getDate()); const mm = addLeadingZero(date.getMonth() + 1); const yyyy = date.getFullYear().toString(); return format.replace('dd', dd).replace('mm', mm).replace('yyyy', yyyy); } // This constant is not strictly necessary but I think it makes the code more readable const ONE_DAY_MSEC = 86400000; // Component const MyComponent = () => { const [date, setDate] = useState(new Date()); // date as a date const [dispDate, setDispDate] = useState(formatDate(new Date())); // date as a formatted string useEffect(() => { setDispDate(formatDate(date)) }, [date, setDispDate]); const handleNextDayClick = useCallback(() => { setDate((current) => new Date(current.getTime() + ONE_DAY_MSEC)) }, [setDate]); const handlePrevDayClick = useCallback(() => { setDate((current) => new Date(current.getTime() - ONE_DAY_MSEC)) }, [setDate]); return ( <div> <div>Date: {dispDate}</div> <button onClick={handlePrevDayClick}>prev day</button> <button onClick={handleNextDayClick}>next day</button> </div> ); } ReactDOM.render(<MyComponent />, document.getElementById('App'));
 <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="App" />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM