Skip to content

Commit

Permalink
fix(taro-weapp/tt): 数组 diff 逻辑更改
Browse files Browse the repository at this point in the history
  • Loading branch information
Chen-jj committed Mar 5, 2019
1 parent a5d9dcf commit 2f82f0c
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 12 deletions.
73 changes: 73 additions & 0 deletions docs/best-practice.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` 就可能显得比较重了,这时候如果想使用全局变量,推荐如下使用。
Expand Down
24 changes: 24 additions & 0 deletions docs/debug.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 8 additions & 6 deletions packages/taro-tt/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
14 changes: 8 additions & 6 deletions packages/taro-weapp/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 2f82f0c

Please sign in to comment.