前几天同事有一个逻辑问题问我,由于我自己有开发任务,导致不能专心的思考那个问题,最后基本凭感觉给了一个思路。回过头来想,同事所遇到的这种场景是很常见的,但是许多人(包括我自己)往往不能很快的想到如何解决,因为这种场景确实包含着看似需要这样实际不需要这样的东西,导致思考时被太多的噪音干扰。
具体场景是这样的:
1. 界面上有个两个元素,一个输入文本框,输入会计期间数(num),一个表格根据 num 自动生成会计期间 (list) 2. 只要 num 变化都需要重新计算 list 3. 编辑时,num 和 list 取自后台数据,不走 2 的逻辑,但是当用户再次改变 num 时,继续走 2 的逻辑 4. 新增时,走 2 的逻辑
基于以上,我们可以写一些伪代码,以下是 list 根据 num 生成的代码:
// 为了简单描述联动关系,采用了 vue3 的相关 api
const num = ref(1)
const list = ref([])
const getListByNum = (num) => {
return new list()
}
watchEffect(() => {
list.value = getListByNum(num.value)
})
接着我们处理编辑的特殊情况:
const num = ref(1)
const list = ref([])
const isEdit = false
const getListByNum = (num) => {
return new list()
}
const handleEdit = (data) => {
num.value = data.num
list.value = data.list
isEdit = true
}
watchEffect(() => {
// 这是我们常常的直觉的思路
// 就是标记当前是否为编辑状态
// 但是这里需要解决的就是,在什么时候还原这个状态
if (isEdit) {
// 思路1. 第一次过后直接重置 isEdit 的状态
isEdit = false
// 这个做法的潜在问题很多
// a. 如果这个 list 的条件还很多,比如还跟着 a 的值变化,那么 a 的值变化以及
// num 的值变化都会导致 watchEffect 触发,导致我们可能不得不控制它触发几次之后
// 再重置状态,甚至在更具体的例子中我们根本不知道会触发几次,这是 vue 的底层调度决定的
// 有可能合并为一次,有可能两次
// b. 在编辑前,我们常常会清除前一次的状态,这就导致清除也会触发这个,于是我们还得判断
// 是不是清除操作导致触发的,比如判断其值为不为空
} else {
list.value = getListByNum(num.value)
}
})
最终的思路:
const num = ref(1)
const list = ref([])
const isNeedBuildList = false
const getListByNum = (num) => {
return new list()
}
const handleEdit = (data) => {
num.value = data.num
list.value = data.list
isNeedBuildList = false
}
// 当用户改变了 num 的时候需要生成
const handleNumChangeFromUser = () => {
isNeedBuildList = true
}
const handleAdd = () => {
isNeedBuildList = true
}
watchEffect(() => {
// 这里我们用一个变量控制是不是需要生成 list 即可
// 这样我们不用关心,生不生成 list 是根据什么样的逻辑
// 只需要关心需不需生成
if (isNeedBuildList) {
list.value = getListByNum(num.value)
}
})
由此我想到了用数学函数来表述这个思路:
// 1. f(x) 因为 x 的变化而变化
f(x) = 3x
// 2. 如何控制它有时候变,有时候不变,那么在数学中我们很容易
//想到,引入一个新的变量,且值为 0 或 1,当 y 为 0 则永远为 0
//当 y 为 1 则保持原逻辑,在数学函数中我们不会想着当 x 怎么怎么样的时候不变
// 而是直接引入新变量
f(x, y) = 3xy
// 3. 无论我们引入多少个因变量,我们总是能通过 y 去控制它
f(x, y, z, w, k) = f(x, z, w,k)y
由此总结的一般性思考就是:
当某个状态根据另一个状态变化,且需要控制这一变化过程在某些情况下是执行,在另外一些情况不执行,我们需要明白的是,我们不应该把某些情况或另外一些情况作为另一状态变化的直接条件,而是把某些情况或另外一些情况作为是否执行这一新状态的直接条件,再把是否执行这一新状态作为某个状态变化的直接条件,实际上另一个状态就变成另两个状态。由此另一个状态我们也可以推广到另一些状态。