You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React状态函数useState为何导致counter变量无法正常递增?

React Todo组件中counter变量重置的原因及修复方案

问题核心原因

你遇到的counter前两次点击都输出0的问题,本质是普通变量与React状态的生命周期差异:

  • 你定义的counter是组件函数内部的普通变量,只要组件触发重渲染(比如调用Settodo更新状态后),整个Todo组件函数会重新执行一遍,var counter = 0这条语句也会再次运行,直接把counter重置为0。
  • 第一次点击ADD按钮时,先打印counter(此时是0),随后调用Settodo更新状态,React触发组件重渲染,counter被重新设为0;第二次点击时,counter又从0开始计数,所以前两次输出都是0。而移除Settodo后,组件不会触发重渲染,counter一直是同一个变量,自然能正常递增。

另外你的代码还存在不符合React设计理念的问题:直接手动操作DOM创建、添加元素,React的核心是用状态驱动视图,应该通过状态管理列表内容,而非手动操作DOM。

修复方案

1. 用useState管理counter和待办列表

把counter和待办列表都改成React状态变量,让React帮你保留状态值,避免重渲染时丢失:

import React, { useState } from 'react'

export default function Todo() {
  // 用useState管理待办列表数组
  const [todoList, setTodoList] = useState([])
  // 用useState管理计数器状态
  const [counter, setCounter] = useState(0)

  const addTodo = () => {
    const input = document.getElementById('input')
    const inputVal = input.value.trim()
    // 空内容不添加
    if (!inputVal) return

    console.log(counter)
    // 更新待办列表:基于旧状态生成新数组
    setTodoList(prevList => [...prevList, { id: `list-val-${counter}`, text: inputVal }])
    // 更新计数器:基于旧值递增
    setCounter(prevCount => prevCount + 1)
    // 清空输入框
    input.value = ''
  }

  return (
    <>
      <center>
        <h1>Todo</h1>
        <input id="input" type="text" />
        <button onClick={addTodo}>ADD</button>
        <div id="Todo-list">
          {/* 用React渲染列表,自动处理DOM更新 */}
          {todoList.map(item => (
            <li key={item.id} id={item.id}>{item.text}</li>
          ))}
        </div>
      </center>
    </>
  )
}

2. 关键改动说明

  • 用useState管理counter,状态值会在组件重渲染时被React保留,不会被重置。
  • 用数组todoList管理所有待办项,通过map方法渲染列表,完全遵循React状态驱动视图的逻辑,避免手动操作DOM带来的混乱。
  • 更新状态时使用函数式更新(比如setCounter(prevCount => prevCount + 1)),确保每次状态更新都基于最新的旧值,避免异步更新导致的错误。

内容的提问来源于stack exchange,提问作者Nikesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 12:37:08