javascript - 选择/取消选择所有复选框的 MobX 同步可观察更新解决方法
问题描述
我有一个复选框列表,顶部有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
所有项目 - 在幕后 MobX 更新了 observable,现在是
false
因为两个数组NOT
相等 - 我们现在添加所有项目并单击所有复选框。
最终结果是没有取消选择,因为我们删除了所有然后添加了所有。因此需要这样做else
。
有没有一种方法可以在代码中不做两次的情况下重构else
它?removeChildren()
请注意,我想避免计算数组difference
并添加/删除需要/缺少的元素。
将它放在那里几乎需要在其旁边添加注释并附上解释等。我可能缺少一些简单的东西或 mobX 等基本的东西。
解决方案
我不是 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 中不维护表单状态,而是将其保持在组件状态,如果其他组件需要它,将当前选定项目的列表推送到商店(为空或其他),这也是一个非常有力的案例。
推荐阅读
- javascript - 从 JS 获取 POST 并从 PHP 读取响应
- android - 在处理 Firestore 规则时,我无法检查文档中是否存在字段
- ubuntu - 如何将 GCC 7.5 降级到 7.4 ?(Ubuntu 18.04)
- c# - 如何获取Microsoft.EntityFrameworkCore.Sqlite 2.2.6版本的dll文件
- python - 如何在 PyQt5 中在 5 秒内隐藏状态栏?
- azure - 通过禁用 RaiseErrorIfClaimsPrincipalAlreadyExists 来允许“幂等注册”是否明智?
- python - 如何判断 setup() 是否正在读取 setup.cfg?
- npm - 如何在 npx 中指定路径(如 npm --prefix)?
- javascript - 用 javascript 点击时将表单替换为另一个表单
- php - 使用php解密AES中的字符串