javascript - Reactjs - 从数组中添加/删除项目并使用复选框存储
问题描述
先决条件
我正在获取在页面加载时显示的帐户列表(Ajax 请求)(旁边有一个复选框)。默认情况下,所有帐户都被选中并添加到商店(redux)。
目标
选中/取消选中复选框时,从数组和存储(redux)中添加/删除帐户:
- 复选框已选中 --> 将帐户添加到数组并存储
- 复选框未选中 --> 从数组和存储中删除帐户
逻辑
我创建了两个单独的动作和减速器:
- 一个管理复选框状态
- 一种用于管理将帐户添加/删除到阵列和存储
在测试我的代码时,它一开始可以正常工作,但最终添加/删除的帐户不正确。问题一定出在 saveAccount() 但不确定我做错了什么?
我的代码
在 ComponentWillMount() 中将数据预填充到存储中:
componentWillMount = () => {
let defaultAccount = this.props.account
let defaultCheckbox = this.props.checkboxStatus
for(let i =0; i < this.props.products.arrangements.items.length; i++){
const data = {}
data['id'] = i
data['isSelected'] = true
data['sortCode'] = this.props.products.arrangements.items[i].sortCode
data['accountNumber'] = this.props.products.arrangements.items[i].accountNumber
data['accountName'] = this.props.products.arrangements.items[i].accountName
defaultAccount = defaultAccount.concat(data)
const checkboxesArray = {}
checkboxesArray['id'] = i
checkboxesArray['checked'] = true
defaultCheckbox = defaultCheckbox.concat(checkboxesArray)
}
this.props.addAccount(defaultAccount)
this.props.toggleCheckbox(defaultCheckbox)
}
显示来自 Ajax 响应的帐户列表 (this.props.products.arrangements.items)
render() {
return (
<div>
{typeof(this.props.products.arrangements.items) !== 'undefined' &&
(Object.keys(this.props.account).length > 0) &&
(typeof(this.props.checkboxStatus) !== 'undefined') &&
(Object.keys(this.props.checkboxStatus).length > 0) &&
(Object.keys(this.props.products.arrangements.items).length > 0) &&
<div>
{this.props.products.arrangements.items.map((item,i) =>
<div className="accountContainer" key={i}>
<Checkbox
required
label={"Account Number "+item.accountNumber+" Product Name "+item.accountName}
value={true}
checked={this.props.checkboxStatus[i].checked === true? true: false}
onChange = {(e) => {
this.toggleChange(this.props.checkboxStatus[i])
this.saveAccount(e, i, item.accountNumber, item.accountName)
}}
/>
</div>
)}
</div>
}
</div>
)
}
选中/取消选中复选框时更新 isSelected 值:
saveAccount = (e, i, accountNumber, productName) => {
const data = {};
data['id'] = i
data['accountNumber'] = accountNumber
data['productName'] = productName
if(this.props.checkboxStatus[i].checked === true){
let accountArray = Array.from(this.props.account)
accountArray[i].isSelected = true
this.props.addAccount(accountArray)
}
else {
let accountArray = Array.from(this.props.account)
accountArray[i].isSelected = false
this.props.addAccount(accountArray)
}
}
减速器
function Eligible(state = { products: {}, account: [], checkboxStatus: [] }, action){
switch (action.type){
case ADD_PRODUCTS:
return {
...state,
products: action.data
}
case ADD_ACCOUNT:
return {
...state,
account: action.data
}
case TOGGLE_CHECKBOX:
return {
...state,
checkboxStatus: action.data
}
default:
return state
}
}
行动
export const ADD_PRODUCTS = 'ADD_PRODUCTS'
export const ADD_ACCOUNT = 'ADD_ACCOUNT'
export const TOGGLE_CHECKBOX = 'TOGGLE_CHECKBOX'
export function addProducts(data){
return {type: ADD_PRODUCTS, data}
}
export function addAccount(data) {
return { type: ADD_ACCOUNT, data}
}
export function toggleCheckbox(data) {
return { type: TOGGLE_CHECKBOX, data}
}
更新复选框状态:
toggleChange = (checkbox) => {
let toggleCheckbox = this.props.checkboxStatus
toggleCheckbox[checkbox.id].checked = !checkbox.checked
this.props.toggleCheckbox(toggleCheckbox)
}
解决方案
我认为 的异步性this.setState
可能会导致问题。
this.state
包含accounts
和checkboxes
:
this.state = {
accounts: [],
checkboxes: []
}
在您的更改事件处理程序中,您调用两个函数:
onChange = {(e) => {
this.toggleChange(this.props.checkboxStatus[i])
this.saveAccount(e, i, item.accountNumber, item.accountName)
}}
第一个切换更改:
toggleChange = (checkbox) => {
let toggleCheckbox = [...this.state.checkboxes];
toggleCheckbox[checkbox.id].checked = !checkbox.checked
this.setState({
checkboxes: toggleCheckbox
})
this.props.toggleCheckbox(this.state.checkboxes)
}
您正在更新状态的 checkboxes 属性(通过 this.setState) - 一切都很好。但在最后一行,你昏倒this.state.checkboxes
了。由于 this.setState 是异步的,这可能不会反映您刚刚所做的更改(您可以toggleCheckbox
改为发送)。
事件处理程序中调用的下一个函数是 saveAccount,它包含(部分):
const addAccountState = this.state
if(this.props.checkboxStatus[i].checked === true){
addAccountState.accounts = addAccountState.accounts.concat(data)
this.setState(addAccountState)
this.props.addAccount(addAccountState.accounts)
}
在这里,您正在获取 this.state 的当前值(由于异步 setState,它可能是旧的)。您更新它的 .accounts 属性,然后将整个内容(包括.accounts
and .checkboxes
)发送到this.setState
.
由于.checkboxes
状态可能是旧的(前一个this.setState
可能尚未触发),这会将旧的 .checkboxes 状态排队以覆盖您尝试保存的新状态toggleChange()
。
可以使用快速而肮脏的修复程序this.setState({accounts: addAccountState.accounts})
,但也可能存在其他问题(例如this.state
直接修改属性)。
因为 setState 是异步的,所以在同一个更新周期的后续调用会覆盖之前的更新,之前的修改会丢失。
关于商店和状态的分离......一种选择可能是根本不单独存储复选框,而是根据选择的帐户来计算它们。
当然,这取决于您的应用程序的需求,因此我将做一些假设以作为示例......
- 您的应用程序需要一个选定帐户的列表
- 您的组件需要显示所有帐户的列表
- 您的组件对每个帐户都有复选框:选中 = 选定 = 应用程序“选定帐户”列表的一部分。
在这种情况下,我将通过 传入选定帐户的列表props
。
在组件中,我将拥有本地状态中所有帐户的列表(如果您的“所有帐户”列表已经通过道具传递,那么只需使用它 - 不需要本地状态)。
在组件的渲染函数中,我将根据帐户是否存在于“选定帐户”列表中来计算是否应选中复选框。如果存在,则对其进行检查。如果不是,则不检查。
然后,当用户单击以选中/取消选中该框时,我将调度该函数以从“选定帐户”列表中添加或删除该帐户,仅此而已。该帐户将被添加或删除,这将导致您的道具更新,这将重新渲染您的组件,这将根据需要选中或取消选中这些框。
这可能不完全符合您特定应用程序的需求,但我希望它能给您一些想法!:)
推荐阅读
- c++ - cmake target_link_libraries 导致目标中的编译器错误
- javascript - 单击按钮 AJAX 方式获取 ID
- mule - 如何创建键值对窗口以在 mule 自定义连接器中添加动态属性,目前使用 mule 3
- reactjs - 如何设置本地环境以在 https 上运行
- sass - 媒体查询中没有继承的 scss 背景属性
- python - 内核照片处理:图像无法出现
- linux - 将 bash 脚本上传到 MAAS 部署的 Ubuntu 机器上
- git - Git 已经安装在 `usr/local/Cellar/git` 下,接下来呢?
- python - 如何使用 joblib 或 pickle 下载经过训练的 BeRT 模型?
- azure - Azure DataFactory 在 Azure Function body 活动中使用变量