React Native:复选框列表结构
React Native: Checkbox List Structure
一个 user
对象有一个引用一个或多个学校对象的数组属性 schools
。我想使用 <List>
和 <CheckBox>
来改变 schools
数组。
我将 user
对象加载到视图中,并加载 listOfSchools
(从应用程序状态)以生成复选框列表:
<List data={listOfSchools} keyExtractor={ item=> item._id } renderItem={({item})=>renderItem(item)} />
renderItem
函数:
const renderItem = (school) => {
return <ListItem
title={school.name}
accessory={()=>renderAccessory(school)}
/>
};
renderAccessory
函数:
const renderAccessory = (school) => {
return <CheckBox checked={() => checkSchool(school._id)} onChange={()=>changeSchool(school._id)} />
}
如果 user.schools
数组中引用了 school._id
,checkSchool
函数 returns 布尔值。 changeSchool
函数在 users.schools
数组中添加或删除 school._id
。
changeSchool
函数:
const changeSchool = (schoolId) => {
let checked = checkSchool(schoolId);
if (!checked) {
// add schoolId to user.schools
} else {
// remove schoolId from user.schools
}
}
这根本行不通。看来无论我用什么来改变状态,复选框都不会更新,user.schools
数组也不会改变。
构建这样一个设计目标的正确方法是什么?
假设您使用 UI Kitten,我可以看出您的 CheckBox
组件的 checked
属性值错误。
checked
prop 需要是 boolean
而不是你那里的 Callable
我会尝试像这样更改代码:
const renderAccessory = (school) => {
const isChecked = checkSchool(school._id);
return <CheckBox checked={isChecked} onChange={()=>changeSchool(school._id)} />
}
如果有帮助请告诉我。
在尝试各种解决方案时,我可以在这里得出一些结论:
- 使用@Cornel Raiu 给出的解决方案,已正确计算已选中和未选中的标志,但是,在 checked/unchecked
的状态下显示不正确
- 我用 Toggle 替换了 Checkbox,只是为了确保它也适用于 iOS
- 我仍然面临的问题是,即使被切换的项目状态正确填充它正在重置
- Toggles的外部容器是List和ListItem,
- 观察到 List 上的 Press 事件实际上使 Checkbox/Toggle 进入正确的显示状态...
解决方案:
经过更长时间的研究和实验,我通过以下方法得到了我的东西 -
我维护了单独的托运项目集合
已存在主条目集合状态,作为列表的输入
每次点击 Checkbox/Toggle,数据的主列表被克隆并复制回其状态
这触发了组件的轻微重新渲染,一切正常。
const [cashTransactions, setCashTransactions] = useState([]); // master data
const [selectedTransactions, setSelectedTransactions] = useState([]); // selected data
const renderItem = ({ item, index }) => (
<ListItem
title={'('+item.id + ') ' + item.firstName + ' ' + item.lastName}
description={Moment(item.createdOn).format('yyyy-MM-DD hh:mm:ss')}
accessoryLeft={selectedTransactions.includes(item.id) ? RadioOnIcon : RadioOffIcon}
accessoryRight={() => checkBoxSpace(item)}
/>
);
const checkBoxSpace = (item) => {
let itemChecked = selectedTransactions.includes(item.id);
return (
<View style={styles.actionContainer}>
<Button size='tiny' status='basic' accessoryLeft={rupeeSymbol}>{item.amount}</Button>
<Toggle checked={itemChecked} status='primary' size='small' onChange={checked => checkboxChecked(item, checked)}></Toggle>
</View>
)
}
const checkboxChecked = (item, checked) => {
console.log('Item -' + item.id + ' ' + checked);
if (checked) {
if (!selectedTransactions.includes(item.id)) {
selectedTransactions.push(item.id);
}
} else {
if (selectedTransactions.includes(item.id)) {
selectedTransactions.pop(item.id);
}
}
console.log('selectedTransactions ' + JSON.stringify(selectedTransactions));
// This is the thing i applied to get it done.
const cloned = [...cashTransactions];
setCashTransactions(cloned);
}
// View
<List
style={styles.container}
data={cashTransactions}
renderItem={renderItem}
/>
一个 user
对象有一个引用一个或多个学校对象的数组属性 schools
。我想使用 <List>
和 <CheckBox>
来改变 schools
数组。
我将 user
对象加载到视图中,并加载 listOfSchools
(从应用程序状态)以生成复选框列表:
<List data={listOfSchools} keyExtractor={ item=> item._id } renderItem={({item})=>renderItem(item)} />
renderItem
函数:
const renderItem = (school) => {
return <ListItem
title={school.name}
accessory={()=>renderAccessory(school)}
/>
};
renderAccessory
函数:
const renderAccessory = (school) => {
return <CheckBox checked={() => checkSchool(school._id)} onChange={()=>changeSchool(school._id)} />
}
如果 user.schools
数组中引用了 school._id
,checkSchool
函数 returns 布尔值。 changeSchool
函数在 users.schools
数组中添加或删除 school._id
。
changeSchool
函数:
const changeSchool = (schoolId) => {
let checked = checkSchool(schoolId);
if (!checked) {
// add schoolId to user.schools
} else {
// remove schoolId from user.schools
}
}
这根本行不通。看来无论我用什么来改变状态,复选框都不会更新,user.schools
数组也不会改变。
构建这样一个设计目标的正确方法是什么?
假设您使用 UI Kitten,我可以看出您的 CheckBox
组件的 checked
属性值错误。
checked
prop 需要是 boolean
而不是你那里的 Callable
我会尝试像这样更改代码:
const renderAccessory = (school) => {
const isChecked = checkSchool(school._id);
return <CheckBox checked={isChecked} onChange={()=>changeSchool(school._id)} />
}
如果有帮助请告诉我。
在尝试各种解决方案时,我可以在这里得出一些结论:
- 使用@Cornel Raiu 给出的解决方案,已正确计算已选中和未选中的标志,但是,在 checked/unchecked 的状态下显示不正确
- 我用 Toggle 替换了 Checkbox,只是为了确保它也适用于 iOS
- 我仍然面临的问题是,即使被切换的项目状态正确填充它正在重置
- Toggles的外部容器是List和ListItem,
- 观察到 List 上的 Press 事件实际上使 Checkbox/Toggle 进入正确的显示状态...
解决方案: 经过更长时间的研究和实验,我通过以下方法得到了我的东西 -
我维护了单独的托运项目集合
已存在主条目集合状态,作为列表的输入
每次点击 Checkbox/Toggle,数据的主列表被克隆并复制回其状态
这触发了组件的轻微重新渲染,一切正常。
const [cashTransactions, setCashTransactions] = useState([]); // master data const [selectedTransactions, setSelectedTransactions] = useState([]); // selected data const renderItem = ({ item, index }) => ( <ListItem title={'('+item.id + ') ' + item.firstName + ' ' + item.lastName} description={Moment(item.createdOn).format('yyyy-MM-DD hh:mm:ss')} accessoryLeft={selectedTransactions.includes(item.id) ? RadioOnIcon : RadioOffIcon} accessoryRight={() => checkBoxSpace(item)} /> ); const checkBoxSpace = (item) => { let itemChecked = selectedTransactions.includes(item.id); return ( <View style={styles.actionContainer}> <Button size='tiny' status='basic' accessoryLeft={rupeeSymbol}>{item.amount}</Button> <Toggle checked={itemChecked} status='primary' size='small' onChange={checked => checkboxChecked(item, checked)}></Toggle> </View> ) } const checkboxChecked = (item, checked) => { console.log('Item -' + item.id + ' ' + checked); if (checked) { if (!selectedTransactions.includes(item.id)) { selectedTransactions.push(item.id); } } else { if (selectedTransactions.includes(item.id)) { selectedTransactions.pop(item.id); } } console.log('selectedTransactions ' + JSON.stringify(selectedTransactions)); // This is the thing i applied to get it done. const cloned = [...cashTransactions]; setCashTransactions(cloned); } // View <List style={styles.container} data={cashTransactions} renderItem={renderItem} />