Prerquisite
我正在获取我在页面加载时显示的帐户列表(Ajax请求)(旁边有一个复选框)。默认情况下,会选择所有帐户并将其添加到商店(redux)。
目标
在阵列中添加/删除帐户&选中/取消选中复选框时存储(redux):
逻辑
我创建了两个单独的动作&减速器:
在测试我的代码时,它在开始时工作正常,但最终添加/删除的帐户不正确。问题必须在savingAccount()中但不确定我做错了什么?
我的代码
在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)
}
答案 0 :(得分:1)
我认为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)
}}
First toggleChange:
toggleChange = (checkbox) => {
let toggleCheckbox = [...this.state.checkboxes];
toggleCheckbox[checkbox.id].checked = !checkbox.checked
this.setState({
checkboxes: toggleCheckbox
})
this.props.toggleCheckbox(this.state.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的当前值(由于async setState,它可能是旧的)。您更新它的.accounts属性,然后将整个内容(包括.accounts
和.checkboxes
)发送到this.setState
。
由于.checkboxes
状态可能已经过时(之前的this.setState
可能尚未解雇),这会将旧的.checkboxes状态排队,以覆盖您尝试保存在{的新状态。 {1}}。
可以使用toggleChange()
进行快速而肮脏的修复,但也可能存在其他问题(例如直接修改this.setState({accounts: addAccountState.accounts})
属性)。
因为setState是异步的,所以后续调用在同一个更新中 循环将覆盖以前的更新,并且之前的更改将会 迷路了。
Beware: React setState is asynchronous!
关于商店和州的分离......一个选项可能是根本不单独存储复选框,而是根据选择的帐户计算它们。
当然,这取决于你的应用需求,所以为了举例,我会做一些假设......
在这种情况下,我会通过this.state
传入选定帐户的列表。
在组件中,我将拥有本地状态下所有帐户的列表(如果您的“所有帐户”列表已经通过道具传递,那么只需使用它 - 不需要本地状态。)
在组件的渲染功能中,我会根据帐户是否存在于“选定帐户”列表中来计算是否应选中该复选框。如果它存在,则检查它。如果没有,不检查。
然后,当用户点击选中/取消选中该框时,我会调度该功能,以便从“选定的帐户”列表中添加或删除该帐户,就是这样。该帐户将被添加或删除,这将导致您的道具更新,这将重新呈现您的组件,这将选中或取消选中相应的框。
这可能并不完全符合您特定应用程序的需求,但我希望它能为您提供一些想法! :)