我有一个复选框列表,其顶部有Select All
复选框。它由字符串observable array
驱动。当用户选中Select All
时,应按check
的所有复选框进行操作,并在随后单击时将其全部取消。非常简单。
有关状态等的一些详细信息:
let arrayB = ['a','b','c'] // List coming from an API etc
let state = observable({
arrayA: [], // <-- nothing is checked by default
get hasAllChecked() {
return ( state.arrayA.length === arrayB.length )
},
})
问题在于,我很好奇这个复选框列表onChange
的处理程序中:
if (!state.hasAllChecked) {
removeChildren()
} else {
removeChildren()
addAllChildren()
}
乍一看,您会问为什么不将其重构为:
removeChildren()
if (!state.hasAllChecked)
addAllChildren()
这是说明原因和步骤:
Deselect All
复选框(同一标签只是标签根据hasAllChecked
的值而更改)if
,所以我们继续remove
所有项目false
,因为两个数组NOT
相等最终结果是未取消选择任何内容,因为我们先删除了所有内容,然后又添加了所有内容。因此,需要该else
。
是否有一种方法可以重构此代码而无需执行else
并且在代码中两次拥有removeChildren()
?请注意,我要避免计算数组difference
并添加/删除所需/缺少的元素。
在其中几乎有必要在注释旁边加上说明等。我可能缺少简单的东西或mobX的基本知识。
答案 0 :(得分:0)
我发现简化此问题的当前解决方法是在lodash
(无论如何目前都在使用它)和_.constant
或类似的方法中进行的:
let hasAllChecked = _.constant(state.hasAllChecked) // <-- freeze value
removeChildren()
if (!state.hasAllChecked)
addAllChildren()
由于有了"freezes"
这个可观察的值并简化了事情。
答案 1 :(得分:0)
我不确定是否100%理解您的要求,但这是通过一个简单的商店操作选择的演示。希望这可能有助于澄清问题!
const items = ["one", "two", "three", "four", "five"];
const store = {
checked: [],
checkAll() {
this.checked.replace(items);
},
get hasAllChecked() {
return this.checked.length === items.length;
},
isChecked(item) {
return this.checked.includes(item);
},
selectItem(item) {
this.isChecked(item) ? this.checked.remove(item) : this.checked.push(item)
},
uncheckAll() {
this.checked.clear();
}
};
decorate(store, {
checked: observable,
checkAll: action,
selectItem: action,
uncheckAll: action
});
const toggleSelectAll = () =>
store.hasAllChecked ? store.uncheckAll() : store.checkAll();
使用该组件的组件可能类似于:
const renderCheckboxItem = (item, i) => {
const checked = store.isChecked(item);
return (
<React.Fragment key={`item-${i}`}>
<input
name={`item-${item}`}
type="checkbox"
checked={checked}
onChange={() => store.selectItem(item)}
/>
<label htmlFor={`item-${item}`}>{item}</label>
</React.Fragment>
);
};
const renderItem = (item, i) => <li key={`selected-item-${i}`}>{item}</li>;
const Selector = observer(() => {
return (
<React.Fragment>
<form>
{items.map(renderCheckboxItem)}
<React.Fragment key="item-select-all">
<input
name="select-all"
type="checkbox"
onChange={toggleSelectAll}
/>
<label htmlFor="select-all">Select all</label>
</React.Fragment>
</form>
<p>Selected items:</p>
<ul>{store.checked.map(renderItem)}</ul>
</React.Fragment>
);
});
在更复杂的设置中,我怀疑您想跟踪具有id而不是简单字符串的对象,因此解决方案也可能会更复杂。我认为,在MobX中不维护表单状态,而是将其保持在组件状态,如果其他组件需要它,则将当前选定项列表推送到商店(空或其他)也很有力。