not very good, because in this case, the child will be repopulated (it was already repopulated)

I would do the algorithm as following:
<code>
refresh(initialNodeWithExpandedChildren) {
  refreshedNodeWithExpandedChildren = new; force population
  if (null) => return null //child no longer exists; client should be able to process this
  if (initial.expanded) {
    refreshInternal(refreshed, initial);
  }
}

refreshInternal(refreshedNodeWithExpandedChildren, initialNodeWithExpandedChildren) {
  getChildren(refreshed);
  for each child {
    new childRefreshedNodeWithExpandedCh; childRefr.node = child
    if (initial.expandedChildren.indexOf(childRefreshed) => recursie
    refreshed.children.add(childRefreshed);
  }
}
</code>

We would have in fact 2 structures:
<code>
NodeWithExpandedChildren { // client -> server
  fullId, expanded, expandedChildren:List
}

and

NodeWithChildren {
  node, children
}