Skip to content

Instantly share code, notes, and snippets.

@wangcaipang
Created May 26, 2017 08:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wangcaipang/31f3166fd980198d825a7d0c1a2ca2f4 to your computer and use it in GitHub Desktop.
Save wangcaipang/31f3166fd980198d825a7d0c1a2ca2f4 to your computer and use it in GitHub Desktop.
react diff patch
export default function diff (parentNode, prevNodeMap, newNodeMap) {
let lastIndex = 0
let lastRightNode = null
let patch = []
let mountIndex = 0
for (let name in newNodeMap) {
if (newNodeMap.hasOwnProperty(name)) {
let newNode = newNodeMap[name]
let prevNode = prevNodeMap[name]
if (prevNode) {
let prevIndex = prevNode.index
if (prevIndex > lastIndex) {
lastIndex = prevIndex
} else {
patch.push({
type: 'move',
node: prevNode,
insertNode: lastRightNode
})
}
lastRightNode = prevNode
prevNode.index = mountIndex++
} else {
patch.push({
type: 'insert',
node: newNode,
insertNode: lastRightNode
})
newNode.index = mountIndex++
lastRightNode = newNode
}
}
}
for (let name in prevNodeMap) {
if (prevNodeMap.hasOwnProperty(name) && !newNodeMap.hasOwnProperty(name)) {
let prevNode = prevNodeMap[name]
patch.push({
type: 'remove',
node: prevNode
})
}
}
function getNodeAfter (parentNode, node) {
return node ? node.nextSibling : parentNode.firstChild
}
patch.forEach(action => {
switch (action.type) {
case 'move':
parentNode.insertBefore(action.node, getNodeAfter(parentNode, action.insertNode))
break
case 'insert':
parentNode.insertBefore(action.node, getNodeAfter(parentNode, action.insertNode))
break
case 'remove':
parentNode.removeChild(action.node)
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment