用传递值||反应钩子问题defaultValue和更新计数器

时间:2020-06-26 19:45:36

标签: javascript reactjs react-hooks setstate use-state

找到以下示例代码和屏幕截图。

两个问题:

  1. counter未正确更新,是否可以写类似setCounter((prev) => { return { counter: prev.counter - value || 1 }});的东西?

  2. setCounter(counter + value || 1)的正确方法是什么 要工作,在缺少实际值的情况下使用1?

找到以下示例代码和屏幕截图。

const Counter = (props) => {
  const [counter, setCounter] = useState(0);

  const handleCounterChange = (action, value) => {
    switch (action) {
      case "+":
        setCounter(counter + value || 1);
        break;
      case "-":
        setCounter(counter - value || 1);
        break;
      default:
        setCounter(counter + value || 1);
        break;
    }
  };

  return (
    <div className={classes.Counter}>
      <CounterOutput value={counter} />
      <CounterControl
        label="+"
        clicked={() => handleCounterChange("+")}
      />
      <CounterControl
        label="-"
        clicked={() => handleCounterChange("-")}
      />
      <CounterControl
        label="+ 5"
        clicked={() => handleCounterChange("+", 5)}
      />
      <CounterControl
        label="- 5"
        clicked={() => handleCounterChange("-", 5)}
      />
    </div>
  );
};

export default Counter;

enter image description here

3 个答案:

答案 0 :(得分:2)

setCounter(counter + value || 1);的问题在于,JS将尝试首先计算counter + value 然后布尔测试。因此,例如,如果您的counter值为1,并且减去了1的值,则结果为0,这是错误的,因此1将保存为counter的新值。这可能不是您想要的。

console.log(100 + undefined || 1); // expect 101 but result is 1
console.log(1 + -1 || 1); // expect 0 but result is 1

您可以将优先级分组,即counter + (value || 1)

console.log(100 + (undefined || 1)); // 101

如果您只是想为value提供默认值1,则可以在签名中进行设置。如果value未定义,则会为其分配1的值。并使用功能状态更新。

const handleCounterChange = (action, value = 1) => {
  switch (action) {
    case "+":
      setCounter(counter => counter + value);
      break;
    case "-":
      setCounter(counter => counter - value);
      break;
    default:
      setCounter(counter => counter + value);
      break;
  }
};

关于这种“减速器”类型模式的补充说明是,如果该操作不是您专门处理的操作,则返回现有状态。

const handleCounterChange = (action, value = 1) => {
  switch (action) {
    case "+":
      setCounter(counter => counter + value);
      break;
    case "-":
      setCounter(counter => counter - value);
      break;
    default:
      // ignore, i.e. don't update state at all
      break;
  }
};

答案 1 :(得分:2)

这里提出了两个出色的重构。我绝对希望通读建议并进行重构。

对于导致不可预测的计数器的原因,假设单击参数进入了状态更新功能,则存在操作顺序问题。考虑这种情况。

值是undefined

从编写上述代码的方式来看,当值为undefined时,我们希望将value的数字添加到counter状态。由于操作顺序,这不是正在发生的事情。这个错误很明显,因为valuecounter经常都是1,所以状态似乎没有改变。

> let value = undefined
undefined
> let counter = 1
undefined
> counter + value || 100
100

最后一条陈述是“加法计数器加undefined”,它是NaN,也是虚假的。在这种情况下,结果将始终是'or'语句100的另一端。

使用括号可以更改操作顺序,并创建所需的行为。

> counter + (value || 100)
101

答案 2 :(得分:0)

本质上来说,这不是一个答案,但是请不要使用额外的不必要功能使您的代码过于复杂。您的逻辑是如此简单,添加了额外的功能使它的读取变得更加复杂,并添加了奇怪的逻辑(默认设置是什么?)


  return (
    <div className={classes.Counter}>
      <CounterOutput value={counter} />
      <CounterControl
        label="+"
        clicked={() => setCounter(state => state+1)}
      />
      <CounterControl
        label="-"
        clicked={() => setCounter(state => state-1)}
      />
      <CounterControl
        label="+ 5"
        clicked={() => setCounter(state => state+5)}
      />
      <CounterControl
        label="- 5"
        clicked={() => setCounter(state => state-5)}
      />
    </div>
  );

如果您希望将其干燥多一点,则可以始终执行以下操作:


  const change = by => () => setCounter(count => count+by)

  return (
    <div className={classes.Counter}>
      <CounterOutput value={counter} />
      <CounterControl
        label="+"
        clicked={change(1)}
      />
      <CounterControl
        label="-"
        clicked={change(-1)}
      />
      <CounterControl
        label="+ 5"
        clicked={change(5)}
      />
      <CounterControl
        label="- 5"
        clicked={change(-5)}
      />
    </div>
  );