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

React中handleIncrement正常,handleDecrement无响应问题求助

问题

正在观看Mosh的React教学视频,已实现Increment和Decrement处理器,二者代码逻辑相似,但handleIncrement可正常工作,handleDecrement却无响应,且控制台无任何报错信息。请问我哪里出错了?

App.js

import React, { Component } from 'react';
import NavBar from './components/navbar';
import Counters from './components/counters';
import './App.css';

class App extends Component {

  state = { 
    counters: [
      { id: 1, value: 4 },
      { id: 2, value: 0 },
      { id: 3, value: 0 },
      { id: 4, value: 0 },
      { id: 5, value: 0 },
    ]
  };

  constructor() {
    super();
    console.log("App - Constructor");
  }

  componentDidMount() {
    // make calls to server
    console.log("App - mounted!");
  }

  handleDelete = (counterId) => {
    console.log('handle Delete: ', counterId);
    const counters = this.state.counters.filter(x => x.id !== counterId );
    this.setState({ counters });
  };

  handleDecrement = (counter) => {
    const counters = [...this.state.counters];
    const index = counters.indexOf(counter);
    counters[index] = {...counter};
    counters[index].value--;
    this.setState(counters);
    console.log('decrement counter', counter);
  };

  handleIncrement = (counter) => {
    const counters = [...this.state.counters];
    const index = counters.indexOf(counter);
    counters[index] = {...counter};
    counters[index].value++;
    this.setState({counters});
    console.log('increment counter', counter);
  };

  handleReset = () => {
    console.log('reset counters');
    const counters = this.state.counters.map(c => {
      c.value = 0;
      return c;
    });
    this.setState({counters});
  };

  render() {
    console.log("App - Rendered");
    return (
      <>
        <NavBar 
          totalCounters={this.state.counters.filter(x => 0 < x.value).length}
        />
        <main role="main" className="container">
          <Counters 
            counters={this.state.counters}
            onDecrement={this.handleDecrement}
            onDelete={this.handleDelete}
            onIncrement={this.handleIncrement}
            onReset={this.handleReset}
          />
        </main>
      </>
    );
  }

};

export default App;

Counter.jsx

import React, { Component } from 'react';
import 'bootstrap/dist/css/bootstrap.css';

class Counter extends Component {
    componentDidUpdate(prevProps, prevState) {
        console.log("prevProps", prevProps);
        console.log("prevState", prevState);
    }

    componentWillUnmount() {

    }

    getBadgeClasses = () => {
        let badge = (this.props.counter.value === 0) ? 'bg-warning' : 'bg-primary';
        return 'badge ' + badge + ' m-2';
    }

    formatCount = () => {
        const { value: count } = this.props.counter;
        return count === 0 ? 'Zero' : count;
    }

    render() { 
        console.log("Counter - Rendered");
        return (
            <div className='row'>
                <div className="col-1">
                    <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
                </div>
                <div className="col">
                    <button 
                        onClick={() => this.props.onIncrement(this.props.counter)} 
                        className='btn btn-secondary btn-sm'>+</button>
                    <button
                        onClick={() => this.props.onDecrement(this.props.counter)}
                        className='btn btn-secondary btn-sm m-2'
                        disabled={this.props.counter.value === 0 ? 'disabled' : ''}>-</button>
                    <button 
                        onClick={() => this.props.onDelete(this.props.counter.id)}
                        className="btn btn-danger btn-sm">x</button>
                </div>
            </div>
        );
    }

}
 
export default Counter;

Counters.jsx

import React, { Component } from 'react';
import Counter from './counter';

class Counters extends Component {
    render() { 
        console.log("Counters - Rendered");
        const { onReset, counters, onDecrement, onDelete, onIncrement } = this.props;
        return (
            <div>
                <button 
                onClick={onReset}
                className="btn btn-primary btn-sm m-2">Reset</button>
                {counters.map(counter =>
                    <Counter 
                        key={counter.id} 
                        onDecrement={onDecrement}
                        onDelete={onDelete} 
                        onIncrement={onIncrement}
                        counter={counter}
                    />
                )}
            </div>
        );
    }
}
 
export default Counters;
问题分析与解决

核心问题在handleDecrement方法的setState调用上:

// 错误写法
this.setState(counters);
// 正确写法(和handleIncrement保持一致)
this.setState({ counters });

React的setState需要接收一个状态对象,你直接传入数组counters会导致状态更新失败,但因为语法合法,所以控制台不会抛出错误。修正后handleDecrement就能正常更新状态了。

另外补充一个规范问题:Counter组件中按钮的disabled属性应该用布尔值控制,而非字符串:

// 错误写法
disabled={this.props.counter.value === 0 ? 'disabled' : ''}
// 正确写法
disabled={this.props.counter.value === 0}

虽然字符串'disabled'在HTML中会被视为真值,但React更推荐用布尔值控制这类属性,代码更符合React的设计规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 07:45:59