原文: React Tutorial – How to Work with Multiple Checkboxes
在 React 中处理多个复选框与使用常规 HTML 复选框的方式完全不同。
所以在本文中,我们将看到如何在 React 中使用多个复选框。
你将学习:
- 如何在 React 中使用复选框作为受控输入
- 如何使用数组 map 和 reduce 方法进行复杂计算
- 如何创建预先填充了某些特定值的特定长度的数组
以及更多。
本文是我的 Mastering Redux 课程的一部分。这是我们将在课程中构建的应用程序的预览。
让我们开始吧。
如何使用单个复选框
让我们从单个复选框功能开始,然后再转到多个复选框。
在本文中,我将使用 React Hooks 语法来创建组件。因此,如果你不熟悉 React Hooks,请查看我的 React Hooks 简介文章。
看看下面的代码:
<div className="App">
Select your pizza topping:
<div className="topping">
<input type="checkbox" id="topping" name="topping" value="Paneer" />Paneer
</div>
</div>
这是一个代码示例。
在上面的代码中,我们只声明了一个复选框,类似于我们声明 HTML 复选框的方式。
因此,我们可以轻松地选中和取消选中复选框,如下所示:

但是要在屏幕上显示它是否被选中,我们需要将其转换为受控输入。
在 React 中,受控输入由状态管理,因此只能通过更改与该输入相关的状态来更改输入值。
看看下面的代码:
export default function App() {
const [isChecked, setIsChecked] = useState(false);
const handleOnChange = () => {
setIsChecked(!isChecked);
};
return (
<div className="App">
Select your pizza topping:
<div className="topping">
<input
type="checkbox"
id="topping"
name="topping"
value="Paneer"
checked={isChecked}
onChange={handleOnChange}
/>
Paneer
</div>
<div className="result">
Above checkbox is {isChecked ? "checked" : "un-checked"}.
</div>
</div>
);
}
这是一个代码示例。
在上面的代码中,我们使用 useState
钩子在组件中声明了 isChecked
状态,初始值为 false
:
const [isChecked, setIsChecked] = useState(false);
然后对于输入复选框,我们添加两个 prop,即 checked
和 onChange
:
<input
...
checked={isChecked}
onChange={handleOnChange}
/>
每当我们单击复选框时,将调用 handleOnChange
函数,我们使用它来设置 isChecked
状态的值。
const handleOnChange = () => {
setIsChecked(!isChecked);
};
因此,如果复选框被选中,我们将 isChecked
值设置为 false
。但是如果未选中该复选框,我们将使用 !isChecked
将值设置为 true
。然后我们将该值传递给 prop checked
的输入复选框。
这样,输入复选框成为受控输入,其值由状态管理。
请注意,在 React 中,即使代码看起来很复杂,也始终建议对输入字段使用受控输入。这保证了输入更改仅发生在 onChange
程序内部。
输入的状态不会以任何其他方式更改,你将始终获得输入状态的正确的和更新的值。
只有在极少数情况下,你可以使用 React ref 以不受控制的方式使用输入。
如何处理多个复选框
现在,让我们看看如何处理多个复选框。
看一下这个代码示例。

在这里,我们显示了配料列表及其相应的价格。根据选择的配料,我们需要显示总量。
以前,对于单个复选框,我们只有 isChecked
状态,我们根据它更改了复选框的状态。
但是现在我们有很多复选框,因此为每个复选框添加多个 useState
调用是不切实际的。
因此,让我们在 state 中声明一个数组,指示每个复选框的状态。
要创建一个等于复选框数量长度的数组,我们可以使用数组 fill
方法,如下所示:
const [checkedState, setCheckedState] = useState(
new Array(toppings.length).fill(false)
);
在这里,我们将具有初始值的状态声明为填充值 false
的数组。
因此,如果我们有 5 个配料,那么 checkedState
状态数组将包含 5 个 false
值,如下所示:
[false, false, false, false, false]
一旦我们选中/取消选中复选框,我们会将相应的 false
更改为 true
,并将 true
更改为 false
。
这是最终的代码示例。
完整的 App.js
代码如下所示:
import { useState } from "react";
import { toppings } from "./utils/toppings";
import "./styles.css";
const getFormattedPrice = (price) => `$${price.toFixed(2)}`;
export default function App() {
const [checkedState, setCheckedState] = useState(
new Array(toppings.length).fill(false)
);
const [total, setTotal] = useState(0);
const handleOnChange = (position) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
const totalPrice = updatedCheckedState.reduce(
(sum, currentState, index) => {
if (currentState === true) {
return sum + toppings[index].price;
}
return sum;
},
0
);
setTotal(totalPrice);
};
return (
<div className="App">
<h3>Select Toppings</h3>
<ul className="toppings-list">
{toppings.map(({ name, price }, index) => {
return (
<li key={index}>
<div className="toppings-list-item">
<div className="left-section">
<input
type="checkbox"
id={`custom-checkbox-${index}`}
name={name}
value={name}
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
<label htmlFor={`custom-checkbox-${index}`}>{name}</label>
</div>
<div className="right-section">{getFormattedPrice(price)}</div>
</div>
</li>
);
})}
<li>
<div className="toppings-list-item">
<div className="left-section">Total:</div>
<div className="right-section">{getFormattedPrice(total)}</div>
</div>
</li>
</ul>
</div>
);
}
让我们理解我们在这里做什么。
我们声明了输入复选框,如下所示:
<input
type="checkbox"
id={`custom-checkbox-${index}`}
name={name}
value={name}
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
在这里,我们从 checkedState
状态添加了一个 checked
属性,对应的值为 true
或 false
。因此,每个复选框都将具有其选中状态的正确值。
我们还添加了一个 onChange
程序,并将选中/取消选中的复选框的索引 index
传递给 handleOnChange
方法。
handleOnChange
程序方法如下所示:
const handleOnChange = (position) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
const totalPrice = updatedCheckedState.reduce(
(sum, currentState, index) => {
if (currentState === true) {
return sum + toppings[index].price;
}
return sum;
},
0
);
setTotal(totalPrice);
};
在这里,我们首先使用数组 map
方法遍历 checkedState
数组。如果传递的 position
参数的值与当前 index
匹配,那么我们反转它的值。然后,如果值为 true
,则使用 !item
将其转换为 false
,如果值为 false
,则将其转换为 true
。
如果 index
与提供的 position
参数不匹配,那么我们不会反转它的值,而只是按原样返回值。
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
// 上面的代码与下面的代码相同
const updatedCheckedState = checkedState.map((item, index) => {
if (index === position) {
return !item;
} else {
return item;
}
});
我使用了三元运算符 ?:
,因为它使代码更短,但你可以使用任何数组方法。
如果你不熟悉 map
或 reduce
等数组方法的工作原理,请查看我写的这篇文章。
接下来,我们将 checkedState
数组设置为 updatedCheckedState
数组。这很重要,因为如果你不更新 handleOnChange
程序中的 checkedState
状态,那么你将无法选中/取消选中该复选框。
这是因为我们使用复选框的 checkedState
值来确定复选框是否被选中(因为它是一个受控输入,如下所示):
<input
type="checkbox"
...
checked={checkedState[index]}
onChange={() => handleOnChange(index)}
/>
请注意,我们创建了一个单独的 updatedCheckedState
变量,并将该变量传递给 setCheckedState
函数。我们在 updatedCheckedState
上使用 reduce
方法,而不是在原始的 checkState
数组上。
这是因为默认情况下,用于更新状态的 setCheckedState
函数是异步的。
仅仅因为你调用了 setCheckedState
函数并不能保证你将在下一行中获得 checkedState
数组的更新值。
所以我们创建了一个单独的变量并在 reduce
方法中使用它。
如果你不熟悉 React 中状态的工作原理,可以阅读这篇文章。
然后为了计算总价,我们使用数组 reduce
方法:
const totalPrice = updatedCheckedState.reduce(
(sum, currentState, index) => {
if (currentState === true) {
return sum + toppings[index].price;
}
return sum;
},
0
);
数组 reduce
方法接收四个参数,其中我们只使用了三个:sum
、currentState
和 index
。如果需要,你可以使用不同的名称,因为它们只是参数。
我们还将 0
作为初始值传递,也称为 sum
参数的 accumulator
值。
然后在 reduce
函数内部,我们检查 checkedState
数组的当前值是否为 true
。
如果为 true
,则表示复选框已选中,因此我们使用 sum + toppings[index].price
添加相应 price
的值。
如果 checkedState
数组的值为 false
,那么我们不会添加它的价格,而只是返回计算出的之前的 sum
值。
然后我们使用 setTotal(totalPrice)
将该 totalPrice
值设置为 total
状态。
通过这种方式,我们能够正确计算所选配料的总价格,如下所示:

这是上述代码的预览链接,你可以自己尝试一下。
谢谢阅读
大多数开发人员都难以理解 Redux 的工作原理。但是每个 React 开发人员都应该知道如何使用 Redux,因为行业项目大多使用 Redux 来管理大型项目。
因此,为了方便你学习,我推出了 Mastering Redux 课程。
在本课程中,你将从零开始学习 Redux,你还将使用 Redux 从零开始构建一个完整的食品订购应用程序。
单击下图加入课程并获得限时折扣优惠,并免费获得我的 Mastering Modern JavaScript 书籍。

想要及时了解有关 JavaScript、React、Node.js 的内容吗?在 LinkedIn 上关注我。