diff --git a/docs/best-practice.md b/docs/best-practice.md index 7258b503b1ad..d0aa9fbb3f35 100644 --- a/docs/best-practice.md +++ b/docs/best-practice.md @@ -306,6 +306,79 @@ componentWillMount () { } ``` +### 小程序数据 diff + +在真正调用小程序的 setData 方法之前,Taro 会把页面或组件的 state 和当前页面或组件的 data 做一次 diff,只对必要更新的数据做 setData,开发者无需手动优化。 + +##### diff 逻辑: + +1. 全等 => 跳过 +2. 新增字段 => 使用新值 +3. 类型不同 => 使用新值 +4. 类型相同、基础数据类型 => 使用新值 +5. 其中一方为数组,另一方不是 => 使用新值 +6. 都为数组、新数组比旧数组短 => 使用新值 +7. 都为数组、新数组长度大于等于旧数组的长度 => 逐项 diff、按路径更新 +8. 其中一方为 null,另一方不是 => 使用新值 +9. 都为对象,新对象缺少旧对象某些属性 => 使用新值 +10. 都为对象,新对象拥有旧对象所有的属性 => 逐项 diff、按路径更新 + +例子: + +```js +// 新值 +const state = { + a: 1, + b: 22, + d: 4, + list: [1], + arr: [1, 'a', true, null, 66], + obj: { + x: 5 + }, + foo: { + x: 8, + y: 10, + z: 0 + } +} + +// 旧值 +const data = { + a: 1, + b: 2, + c: 3, + list: [1, 2, 3], + arr: [1, 2, 3], + obj: { + x: 10, + y: 8 + }, + foo: { + x: 'xxx', + y: 10 + } +} + +diff(data, state) +/** + * diff 结果 +{ + b: 22, + d: 4, + list: [ 1 ], + 'arr[1]': 'a', + 'arr[2]': true, + 'arr[3]': null, + 'arr[4]': 66, + obj: { x: 5 }, + 'foo.x': 8, + 'foo.z': 0 +} +*/ +``` + + ## 全局变量 在 Taro 中推荐使用 `Redux` 来进行全局变量的管理,但是对于一些小型的应用, `Redux` 就可能显得比较重了,这时候如果想使用全局变量,推荐如下使用。 diff --git a/docs/debug.md b/docs/debug.md index 15be329d9118..5a38bb757ae3 100644 --- a/docs/debug.md +++ b/docs/debug.md @@ -17,6 +17,30 @@ title: Debug 指南 ### 没有任何报错,但显示的结果不如预期 +#### 被 diff 逻辑过滤 + +此问题发生在页面或组件**更新**时。 + +在调用小程序的 setData 方法前,Taro 会把 state 与 data 做一次 [diff](https://nervjs.github.io/taro/docs/best-practice.html#小程序数据-diff)。 + +如果 state 与 data 的某个属性值没有变化,很有可能就不会重新 setData 该属性,导致页面或组件没有正确更新。 + +这种问题多出现在小程序的表单组件中,例如以下两个 issue:[#1981](https://github.com/NervJS/taro/issues/1981)、[#2257](https://github.com/NervJS/taro/issues/2257)。因为小程序一些表单组件为非受控组件,表单更新时,对应 value 值的 data 并不会更新,导致 data 值还是初始值。如果再 setState 此属性为初始值,由于 diff 逻辑判断属性值没有变化,不会 setData 此属性,导致视图没有更新。正确做法是在表单组件的 update 事件中 setData value 为当前值,保证 data 与表单显示值保持一致。 + +##### debug diff + +开发者可以在开发者工具中找到 taro 运行时库,在 diff 方法前后打断点或 log,观察 **state**、**小程序 data** 和 **diff 后将要被 setData 的数据**,这种排查有助定位很多**视图更新**问题。 + +##### 微信小程序,增加数组元素无法正确更新数组 length + +增加数组元素时,经 diff 后会按路径更新。但由于微信小程序自身 bug,按路径更新数组时,数组 length 不会正确更新。详见 [#882](https://github.com/NervJS/taro/issues/882) + +此问题只出现于微信小程序,[微信官方说法是暂不修复](https://developers.weixin.qq.com/community/develop/doc/000c8a7eeb45e8b018b72f01356800)。 + +推荐做法是新开一个 state 值来同步 length 变化。 + +#### 编译模板出错 + 这时候很可能是编译模板出现了错误。例如中 [#2285](https://github.com/NervJS/taro/issues/2258) 中,题主写了两个嵌套循环,在第二个循环中无法正确地访问到第一个循环声明的 `index` 变量: ```jsx diff --git a/packages/taro-tt/src/util.js b/packages/taro-tt/src/util.js index 070c80d53755..bf6add159902 100644 --- a/packages/taro-tt/src/util.js +++ b/packages/taro-tt/src/util.js @@ -111,10 +111,11 @@ function diffArrToPath (to, from, res = {}, keyPrev = '') { if (arrTo !== arrFrom) { res[targetKey] = toItem } else if (arrTo && arrFrom) { - if (toItem.length === fromItem.length) { - diffArrToPath(toItem, fromItem, res, `${targetKey}`) - } else { + if (toItem.length < fromItem.length) { res[targetKey] = toItem + } else { + // 数组 + diffArrToPath(toItem, fromItem, res, `${targetKey}`) } } else { if (!toItem || !fromItem || keyList(toItem).length < keyList(fromItem).length) { @@ -166,10 +167,11 @@ export function diffObjToPath (to, from, res = {}, keyPrev = '') { if (arrTo !== arrFrom) { res[targetKey] = toItem } else if (arrTo && arrFrom) { - if (toItem.length === fromItem.length) { - diffArrToPath(toItem, fromItem, res, `${targetKey}`) - } else { + if (toItem.length < fromItem.length) { res[targetKey] = toItem + } else { + // 数组 + diffArrToPath(toItem, fromItem, res, `${targetKey}`) } } else { // null diff --git a/packages/taro-weapp/src/util.js b/packages/taro-weapp/src/util.js index 2355941129c2..caddf3141b0e 100644 --- a/packages/taro-weapp/src/util.js +++ b/packages/taro-weapp/src/util.js @@ -111,10 +111,11 @@ function diffArrToPath (to, from, res = {}, keyPrev = '') { if (arrTo !== arrFrom) { res[targetKey] = toItem } else if (arrTo && arrFrom) { - if (toItem.length === fromItem.length) { - diffArrToPath(toItem, fromItem, res, `${targetKey}`) - } else { + if (toItem.length < fromItem.length) { res[targetKey] = toItem + } else { + // 数组 + diffArrToPath(toItem, fromItem, res, `${targetKey}`) } } else { if (!toItem || !fromItem || keyList(toItem).length < keyList(fromItem).length) { @@ -166,10 +167,11 @@ export function diffObjToPath (to, from, res = {}, keyPrev = '') { if (arrTo !== arrFrom) { res[targetKey] = toItem } else if (arrTo && arrFrom) { - if (toItem.length === fromItem.length) { - diffArrToPath(toItem, fromItem, res, `${targetKey}`) - } else { + if (toItem.length < fromItem.length) { res[targetKey] = toItem + } else { + // 数组 + diffArrToPath(toItem, fromItem, res, `${targetKey}`) } } else { // null