React hooks 传值问题 || defaultValue 和更新计数器
React hooks problem with passing value || defaultValue and updating counter
在下面找到示例代码和屏幕截图。
两个问题:
counter
没有正确更新,是否允许写类似 setCounter((prev) => { return { counter: prev.counter - value || 1 }});
的内容?
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;
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;
}
};
关于此“reducer”类型模式的旁注是 return 如果操作不是您专门处理的操作,则现有状态。
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;
}
};
本身不是答案,但不要使用额外的不必要功能使您的代码过于复杂。您的逻辑非常简单,添加额外的功能会使阅读变得更加复杂并添加奇怪的逻辑(默认情况下是什么?)
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>
);
此处提出了一些出色的重构。我绝对想通读建议并进行重构。
至于不可预测计数器的原因,假设点击参数进入状态更新函数,则存在操作顺序问题。考虑这种情况。
值为 undefined
从上面代码的写法来看,当值为undefined
时,我们希望在counter
状态下增加一个value
数字。由于操作顺序,这不是正在发生的事情。这个错误隐藏在众目睽睽之下,因为通常 value
和 counter
都是 1
,所以看起来状态没有改变。
> let value = undefined
undefined
> let counter = 1
undefined
> counter + value || 100
100
最后一条语句说“累加计数器加上 undefined
”,这是 NaN
,也是假的。这种情况下的结果将始终是 'or' 语句的另一面,100
.
使用括号更改操作顺序,并创建所需的行为。
> counter + (value || 100)
101
在下面找到示例代码和屏幕截图。
两个问题:
counter
没有正确更新,是否允许写类似setCounter((prev) => { return { counter: prev.counter - value || 1 }});
的内容?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;
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;
}
};
关于此“reducer”类型模式的旁注是 return 如果操作不是您专门处理的操作,则现有状态。
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;
}
};
本身不是答案,但不要使用额外的不必要功能使您的代码过于复杂。您的逻辑非常简单,添加额外的功能会使阅读变得更加复杂并添加奇怪的逻辑(默认情况下是什么?)
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>
);
此处提出了一些出色的重构。我绝对想通读建议并进行重构。
至于不可预测计数器的原因,假设点击参数进入状态更新函数,则存在操作顺序问题。考虑这种情况。
值为 undefined
从上面代码的写法来看,当值为undefined
时,我们希望在counter
状态下增加一个value
数字。由于操作顺序,这不是正在发生的事情。这个错误隐藏在众目睽睽之下,因为通常 value
和 counter
都是 1
,所以看起来状态没有改变。
> let value = undefined
undefined
> let counter = 1
undefined
> counter + value || 100
100
最后一条语句说“累加计数器加上 undefined
”,这是 NaN
,也是假的。这种情况下的结果将始终是 'or' 语句的另一面,100
.
使用括号更改操作顺序,并创建所需的行为。
> counter + (value || 100)
101