经纬志
首页 / 实战手册 / deck.gl 可视化

两个图层 id 撞了,删一个另一个也没了

先看结论

图例里关掉“基站”层,结果“告警”层也一起消失;再打开,两个层都回来了。

最后验证 2026-11-03 · 多技术栈 · 更新 2026-10-29 · 引用本文

现象

切换任一层显隐,另一层跟着变化。控制台出现重复 id 的提示, 但渲染结果看起来“只有一个层”。打印图层列表只有一条记录,而代码里明明创建了两个。

原因

deck.gl 用 id 作为图层的唯一标识,在两次 setProps 之间做差分: 相同 id 视为同一个图层,只更新属性,不新增实例。 两个图层共用 'points' 这样的通用 id,后一个会覆盖前一个。

动态生成 id 时也容易撞:用数组下标拼 id,删除元素后下标整体前移, 导致旧图层被复用、状态错乱。

排查过程

打印当前图层列表,看数量是否与代码中创建的数量一致:

deck.layerManager.getLayers().forEach(function (l, i) {
  console.log(i, l.id, l.constructor.layerName, l.props.visible);
});
// 0 points ScatterplotLayer true
// 只有一条,但代码创建了两个

解决方案

给每个图层一个带业务前缀的唯一 id,不要用 'points'、'layer1' 这类名字:

var layers = [
  new deck.ScatterplotLayer({
    id: 'station-points',
    data: stations,
    getPosition: function (d) { return [d.lng, d.lat]; },
    getRadius: 6,
    radiusUnits: 'pixels',
    getFillColor: [23, 162, 184]
  }),
  new deck.ScatterplotLayer({
    id: 'alarm-points',
    data: alarms,
    getPosition: function (d) { return [d.lng, d.lat]; },
    getRadius: 9,
    radiusUnits: 'pixels',
    getFillColor: [220, 53, 69],
    pickable: true
  })
];

显隐切换不要重建图层列表,用 visible 属性。这样 id 稳定,差分也简单:

function buildLayers(opts) {
  return [
    new deck.ScatterplotLayer({
      id: 'station-points',
      data: stations,
      visible: opts.showStations,
      getPosition: function (d) { return [d.lng, d.lat]; },
      getRadius: 6,
      radiusUnits: 'pixels'
    }),
    new deck.ScatterplotLayer({
      id: 'alarm-points',
      data: alarms,
      visible: opts.showAlarms,
      getPosition: function (d) { return [d.lng, d.lat]; },
      getRadius: 9,
      radiusUnits: 'pixels'
    })
  ];
}

图层由循环生成时,用业务主键而不是下标拼 id:

groups.forEach(function (g) {
  layers.push(new deck.GeoJsonLayer({
    id: 'district-' + g.code,        // 用行政区代码,删除元素也不会撞
    data: g.geojson,
    filled: true,
    getFillColor: g.color
  }));
});

验证

getLayers() 的数量与创建数一致。 关闭基站层后,告警层仍显示;两层同时打开时,后画的层覆盖先画的层,符合预期。 连续切换五次显隐,图层实例数保持稳定,不持续增长。

id 是状态的一部分:不要在 id 里拼随机数或时间戳。 每次渲染都生成新 id,deck.gl 会把旧图层全部销毁重建, 表现为画面闪烁、拾取状态丢失、内存缓慢上涨。

引用本文

经纬志(2026)。《两个图层 id 撞了,删一个另一个也没了》。https://www.jingweizhi.com/cookbook/deckgl-layer-id-duplicate.html(访问日期 2026-11-03)。