setProps 改了数据,图层却纹丝不动
点了筛选按钮,控制台里的数组确实变了,地图上的点一个没少,颜色也没变。
现象
每次筛选都调用 deck.setProps({ layers: [newLayer] }),但画面没有变化。
只有手动缩放地图触发重绘时,偶尔会闪一下新的结果。
没有报错,deck.layerManager.getLayers() 里的图层对象也是新的。
原因
deck.gl 用图层 id 加属性做浅比较来决定是否更新。
以下几种写法会让它认为“没有变化”:
| 写法 | 结果 |
|---|---|
同一个数组 push/splice 后原样传入 | 引用未变,跳过更新 |
| 同一个图层实例反复传入 | 属性未变,跳过更新 |
数据变了但只改了 getColor 依赖的字段 | 访问器结果未重算,颜色不变 |
在 deck.setProps 之外直接改 layer.props.data | 不触发 diff |
排查过程
- 打印
deck.layerManager.getLayers().map(l => l.id),确认图层确实被替换。 - 打印
deck.props.layers[0].props.data.length,看数据长度是否变化。 - 给
ScatterplotLayer加一个onDataLoad回调,确认数据是否被重新读取。
解决方案
每次都传新数组与新图层实例。最稳妥的做法是把数据转换放进
useMemo 或缓存函数里,避免每帧重建大数组:
function buildLayer(list) {
return new deck.ScatterplotLayer({
id: 'stations',
data: list, // 必须是新数组
getPosition: function (d) { return [d.lng, d.lat]; },
getRadius: 8,
radiusUnits: 'pixels',
getFillColor: function (d) {
return d.status === 'alarm' ? [220, 53, 69] : [23, 162, 184];
},
pickable: true
});
}
function render(list) {
deck.setProps({ layers: [buildLayer(list.slice())] });
}
只改访问器读取的字段时,用 updateTriggers 告诉 deck.gl 重新计算。
适合数据对象不变、但属性被就地更新的场景:
new deck.ScatterplotLayer({
id: 'stations',
data: stations,
getPosition: function (d) { return [d.lng, d.lat]; },
getFillColor: function (d) { return d.color; },
updateTriggers: {
getFillColor: [filterVersion] // 版本号变化即重算
}
});
使用 React 时,把 layers 作为 DeckGL 的 prop 传入,
不要在 effect 里手动调 setProps,两套更新机制会互相覆盖:
const layers = React.useMemo(function () {
return [buildLayer(filteredData)];
}, [filteredData]);
return <DeckGL layers={layers} viewState={viewState} controller />;
验证
筛选后点数立即变化,不需要拖动地图才刷新。
在 onAfterRender 里读 layer.props.data.length,
与实际筛选结果一致。连续切换筛选条件三次,每次都正确。
别在渲染里改数据:在 getColor 之类的访问器里修改
d 的字段,会导致同一帧内多次调用结果不一致,
画面出现部分更新。数据转换应在图层创建之前完成。
经纬志(2026)。《setProps 改了数据,图层却纹丝不动》。https://www.jingweizhi.com/cookbook/deckgl-layer-not-refresh.html(访问日期 2026-11-03)。