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

无需转数组高效对比两数字对应位整数?React动画优化问询

Optimizing Digit Comparison for Robinhood-Style Number Animation

Great question! Your current implementation works, but we can streamline the digit comparison logic by using pure mathematical operations instead of converting numbers to strings and arrays. This approach is more efficient, cleaner, and handles edge cases like carry-over/borrow (e.g., 1000 → 999 or 999 → 1000) more reliably.

Core Idea

Instead of splitting numbers into string arrays, we'll extract each digit using modulo (%) and integer division (Math.floor()), starting from the least significant digit (rightmost). We'll also track carry-over/borrow states to handle cases where digits roll over (like 9 → 0 when incrementing, or 0 → 9 when decrementing).

Refactored Code

First, let's update the checkNums function and adjust the incrementTotal method to use numeric values directly:

Parent Component

class Parent extends React.Component {
  state = {
    isCreateScenarioModalVisible: false,
    isExpressModalVisible: false,
    total: 0,
    truesArr: []
  };

  // New optimized digit comparison logic
  checkNums = (oldTotal, newTotal) => {
    const truesArr = [];
    let oldNum = Math.abs(oldTotal);
    let newNum = Math.abs(newTotal);
    const isIncrease = newTotal > oldTotal;

    // Handle sign difference (e.g., -1 → 0 or 0 → -1)
    if (Math.sign(oldTotal) !== Math.sign(newTotal)) {
      const maxLength = Math.max(oldNum.toString().length, newNum.toString().length);
      for (let i = 0; i < maxLength; i++) {
        truesArr.push(isIncrease ? false : true);
        oldNum = Math.floor(oldNum / 10);
        newNum = Math.floor(newNum / 10);
      }
      // Add/remove sign digit as needed
      if (newTotal < 0) truesArr.push(true);
      if (oldTotal < 0) truesArr.pop();
    } else {
      // Process each digit until both numbers are reduced to 0
      while (oldNum > 0 || newNum > 0) {
        const oldDigit = oldNum % 10;
        const newDigit = newNum % 10;
        let state = null;

        if (isIncrease) {
          // Increment case: mark digits affected by increase or carry-over
          state = (newDigit !== oldDigit) ? false : null;
        } else {
          // Decrement case: mark digits affected by decrease or borrow
          state = (newDigit !== oldDigit) ? true : null;
        }

        truesArr.push(state);
        oldNum = Math.floor(oldNum / 10);
        newNum = Math.floor(newNum / 10);
      }
    }

    // Reverse to match left-to-right digit order
    this.setState({ truesArr: truesArr.reverse() });
  };

  incrementTotal = (arg) => {
    const newTotal = this.state.total + arg;
    // Pass old and new numeric values directly
    this.checkNums(this.state.total, newTotal);
    this.setState({ total: newTotal }, () => {
      console.log(this.state.truesArr);
    });
    setTimeout(() => {
      this.setState({ truesArr: [] });
    }, 500);
  };

  render() {
    return (
      <div>
        <div>
          {this.state.total.toString().split("").map((num, i) => {
            return <Num key={i} num={num} color={this.state.truesArr[i]} />;
          })}
        </div>
        <div onClick={() => this.incrementTotal(1)}>+1</div>
        <div onClick={() => this.incrementTotal(-1)}>-1</div>
      </div>
    );
  }
}

export default Parent;

Child Component (Unchanged)

class Num extends React.Component {
  constructor(prop) {
    super(prop);
  }

  render() {
    let className;
    if (this.props.color === true) {
      className = 'red';
    } else if (this.props.color === false) {
      className = 'green';
    } else {
      className = 'norm';
    }
    return <p className={className}>{this.props.num}</p>;
  }
}

export default Num;

Key Improvements

  • No String/Array Conversion: Uses pure math to extract digits, which is faster and avoids edge cases with string handling (like negative signs).
  • Handles Carry/Borrow: Properly identifies all digits affected by carry-over (e.g., 999 → 1000: all three 9s and the new leading 1 get green animations) or borrow (e.g., 1000 → 999: all four digits get red animations).
  • Negative Number Support: Correctly processes sign changes (e.g., 0 → -1 or -1 → 0) by adjusting the animation array for the sign digit.
  • Simpler Logic: Reduces conditional complexity by focusing on whether digits changed, rather than comparing raw values directly.

Example Test Cases

  • 1000 → 1001: Only the last digit gets false (green animation).
  • 1000 → 999: All four digits get true (red animations).
  • 999 → 1000: All three original digits plus the new leading 1 get false (green).
  • 0 → -1: The - and 1 get true (red).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:18:34