Tengo un archivo fuente más grande que es bastante complejo, así que por ahora me estoy saltando el ejemplo en ejecución. Intentaré crear un ejemplo simple de la fila con la pregunta principal y crearé un ejemplo completamente nuevo a pedido:
let newSelection = parentSelection.selectAll(".myChildren") .data(changedData,d => baseData.id + "/" + d.id);
La idea es que newData se calcule a partir de una matriz en baseData. El código podría obtener (1) modificaciones a los datos existentes o (2) completar nuevos objetos baseData. Debería (1) modificar solo los nodos HTML relevantes o (2) eliminar todos los nodos y reemplazarlos. Es por eso que uso baseData.id en la función clave (o, en este caso, la expresión Lambda).
Sin embargo, no funciona. Cambiar el baseData (y por lo tanto, baseData.id) da como resultado que los nodos se reutilicen siempre que tanto los datos antiguos como los nuevos tengan elementos con ID de elemento idénticos. IE, la selección de entrada tiene un tamaño de 0 o al menos demasiado pequeño, mientras que newSelection contiene hasta todos los elementos. Miré el código fuente de D3.js y dice:
for (i = 0; i < dataLength; ++i) { keyValue = key.call(parent, data[i], i, data) + ""; if (node = nodeByKeyValue.get(keyValue)) { update[i] = node; node.__data__ = data[i]; nodeByKeyValue.delete(keyValue); } else { enter[i] = new EnterNode(parent, data[i]); } }
key es la función que obtiene de la llamada externa. Como se trata de un cierre, toma el baseData.id desde el momento de su creación. Por lo tanto, mi observación anterior parece estar justificada por la teoría. De hecho, podría resolver mi problema usando un poco más de memoria y almacenando la clave completa al calcular los datos modificados.
Aún así, quedan dos preguntas: