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

React/JS面试计数器实现方案优化咨询

面试计数器任务优化实现

面试任务要求

  • 从0开始,每次将计数加1,直到达到10
  • 实现一个函数,当数值大于0时,每次减2直到变为0,数值不能小于0
  • 实现一个函数,每次将计数加2,直到达到10

原实现代码

import React, { useState, useEffect } from "react";

export default function App() {
  const [count, setCount] = useState(0);
  const [incrementBy1, SetIncBy1] = useState(false);
  const [incrementBy2, SetIncBy2] = useState(false);
  const [decrementBy2, SetDecBy2] = useState(false);
  const [reset, setReset] = useState(false);

  const addBy1 = () => {
    setCount((count) => count + 1);
  };
  const addBy2 = () => {
    setCount((count) => count + 2);
  };
  const subBy2 = () => {
    setCount((count) => count - 2);
  };

  useEffect(() => {
    if (count < 10 && incrementBy1 && !reset) {
      setTimeout(addBy1, 1000);
      // setReset(false);
    }
    if (count < 10 && incrementBy2 && !reset) {
      setTimeout(addBy2, 1000);
      // setReset(false);
    }
    if (count > 0 && count % 2 === 0 && decrementBy2) {
      setTimeout(subBy2, 1000);
      setReset(false);
    }

    if (
      count > 0 &&
      !reset &&
      !incrementBy1 &&
      !incrementBy2 &&
      !decrementBy2
    ) {
      setReset(true);
    }

    if (count > 0 && reset && !incrementBy1 && !incrementBy2 && !decrementBy2) {
      setReset(false);
      setCount(0);
    }

    if (count === 0 && decrementBy2) {
      SetDecBy2(false);
      setReset(false);
    }

    if (count < 0) {
      setCount(0);
    }

    console.log(incrementBy2, reset);
  }, [count, incrementBy1, incrementBy2, decrementBy2, reset]);

  const startIncrementCounter = () => {
    if (SetIncBy2) {
      SetIncBy2(false);
    }
    if (SetDecBy2) {
      SetDecBy2(false);
    }
    SetIncBy1(true);
  };

  const startDecrementBy2 = () => {
    if (SetIncBy2) {
      SetIncBy2(false);
    }
    if (SetIncBy1) {
      SetIncBy1(false);
    }
    SetDecBy2(true);
  };

  const startIncrementBy2 = () => {
    if (SetIncBy1) {
      SetIncBy1(false);
    }
    if (SetDecBy2) {
      SetDecBy2(false);
    }
    SetIncBy2(true);
  };

  const handleReset = () => {
    SetIncBy1(false);
    SetIncBy2(false);
    SetDecBy2(false);
    setReset(true);
    setCount(0);
  };

  return (
    <div
      className="App"
      style={{
        display: "flex",
        flexDirection: "column",
        justifyContent: "center",
        alignItems: "center",
        width: "100vw"
      }}
    >
      <h1>Counter!</h1>
      <h2>{count}</h2>
      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "space-evenly",
          maxWidth: 600
        }}
      >
        <button
          disabled={incrementBy1 || incrementBy2 || decrementBy2}
          onClick={startIncrementCounter}
        >
          Start Counter
        </button>
        <button disabled={count === 0} onClick={startDecrementBy2}>
          Decrement By 2
        </button>
        <button
          disabled={
            incrementBy1 || incrementBy2 || decrementBy2 || count % 2 !== 0
          }
          onClick={startIncrementBy2}
        >
          Increment By 2
        </button>
        <button
          disabled={
            (!incrementBy1 && !incrementBy2 && !decrementBy2) || count === 0
          }
          onClick={handleReset}
        >
          reset
        </button>
      </div>
      
      </div>
    </div>
  );
}

优化思路与实现

原代码存在状态冗余、useEffect逻辑复杂、未清理定时器可能引发异常等问题,下面是更简洁易维护的优化版本:

优化点说明

  1. 合并状态:用单个currentAction状态替代多个布尔状态,明确当前执行的操作类型(none/inc1/inc2/dec2)
  2. 定时器管理:用useRef存储定时器ID,在组件卸载或操作切换时清理定时器,避免内存泄漏和重复触发
  3. 逻辑拆分:将每个操作的执行逻辑封装,代码结构更清晰
  4. 简化判断:按钮禁用状态基于currentAction和count直接判断,减少冗余逻辑

优化后的代码

import React, { useState, useEffect, useRef } from "react";

export default function App() {
  const [count, setCount] = useState(0);
  const [currentAction, setCurrentAction] = useState('none'); // none/inc1/inc2/dec2
  const timerRef = useRef(null);

  // 执行计数操作
  const executeAction = () => {
    switch(currentAction) {
      case 'inc1':
        setCount(prev => {
          const newCount = prev + 1;
          // 达到10时停止操作
          if(newCount >= 10) setCurrentAction('none');
          return newCount;
        });
        break;
      case 'inc2':
        setCount(prev => {
          const newCount = prev + 2;
          if(newCount >= 10) setCurrentAction('none');
          // 确保不超过10
          return Math.min(newCount, 10);
        });
        break;
      case 'dec2':
        setCount(prev => {
          const newCount = prev - 2;
          // 到达0时停止操作
          if(newCount <= 0) {
            setCurrentAction('none');
            return 0;
          }
          return newCount;
        });
        break;
      default:
        break;
    }
  };

  // 启动/切换操作
  useEffect(() => {
    // 清理之前的定时器
    if(timerRef.current) clearTimeout(timerRef.current);

    // 当前有操作时启动定时器
    if(currentAction !== 'none') {
      timerRef.current = setTimeout(executeAction, 1000);
    }

    // 组件卸载时清理定时器
    return () => {
      if(timerRef.current) clearTimeout(timerRef.current);
    };
  }, [currentAction, count]);

  // 开始加1操作
  const startInc1 = () => setCurrentAction('inc1');
  // 开始加2操作
  const startInc2 = () => setCurrentAction('inc2');
  // 开始减2操作
  const startDec2 = () => setCurrentAction('dec2');
  // 重置计数器
  const handleReset = () => {
    setCurrentAction('none');
    setCount(0);
  };

  return (
    <div
      className="App"
      style={{
        display: "flex",
        flexDirection: "column",
        justifyContent: "center",
        alignItems: "center",
        width: "100vw",
        gap: '20px'
      }}
    >
      <h1>Counter!</h1>
      <h2>{count}</h2>
      <div
        style={{
          display: "flex",
          gap: '15px',
          alignItems: "center"
        }}
      >
        <button
          disabled={currentAction !== 'none'}
          onClick={startInc1}
        >
          Start Counter (+1)
        </button>
        <button
          disabled={count === 0 || currentAction !== 'none'}
          onClick={startDec2}
        >
          Decrement By 2
        </button>
        <button
          disabled={
            currentAction !== 'none' || count % 2 !== 0 || count >= 10
          }
          onClick={startInc2}
        >
          Increment By 2
        </button>
        <button
          disabled={currentAction === 'none' && count === 0}
          onClick={handleReset}
        >
          Reset
        </button>
      </div>
    </div>
  );
}

总结

优化后的代码大幅减少了状态数量,逻辑更直观易懂,添加了定时器清理机制避免潜在问题,同时保持了所有需求的实现,更符合React组件的最佳实践,也更容易扩展和维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 12:21:13