Skip to content

Commit

Permalink
实现组件更新功能
Browse files Browse the repository at this point in the history
  • Loading branch information
jindy committed Jun 18, 2022
1 parent 39ed1f4 commit 496b02a
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 15 deletions.
34 changes: 34 additions & 0 deletions example/ComponentUpdate/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

import { h, ref } from '../../lib/guide-mini-vue.esm.js'
import Child from './Child.js'
export const App = {
name: 'App',
setup() {
const msg = ref('123')
const count = ref(1)
window.msg = msg
const changeChildProps = () => {
msg.value = '456'
}
const changeCount = () => {
count.value++
}
return {
msg,
count,
changeChildProps,
changeCount
}
},
render() {
return h('div', {},
[
h('div', {}, '你好'),
h('button', { onClick: this.changeChildProps }, 'change child props'),
h(Child, { msg: this.msg }),
h('button', { onClick: this.changeCount }, 'change self count'),
h('p', {}, 'count:' + this.count)
]
)
}
}
8 changes: 8 additions & 0 deletions example/ComponentUpdate/Child.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { h } from '../../lib/guide-mini-vue.esm.js'
export default {
name: 'Child',
setup(props, { emit }) {},
render(proxy) {
return h('div', {}, [h('div', {}, 'child - props - msg:' + this.$props.msg)])
}
}
16 changes: 16 additions & 0 deletions example/ComponentUpdate/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>component update</title>
</head>

<body>
<div id="app"></div>
<script type="module" src="./main.js"></script>
</body>

</html>
6 changes: 6 additions & 0 deletions example/ComponentUpdate/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

import { createApp } from '../../lib/guide-mini-vue.esm.js'
import { App } from './App.js'

const rootContainer = document.querySelector('#app')
createApp(App).mount(rootContainer)
52 changes: 47 additions & 5 deletions lib/guide-mini-vue.cjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ function createVNode(type, props, children) {
type,
props,
children,
component: null,
key: props && props.key,
shapeFlag: getShapeFlag(type),
el: null,
Expand Down Expand Up @@ -294,6 +295,7 @@ function initProps(instance, rawProps) {
const publicPropertiesMap = {
$el: (i) => i.vnode.el,
$slots: (i) => i.slots,
$props: (i) => i.props,
};
const PublicInstanceProxyHandlers = {
get({ _: instance }, key) {
Expand Down Expand Up @@ -344,6 +346,7 @@ function createComponentInstance(vnode, parent) {
isMounted: false,
subTree: {},
emit: () => { },
next: null,
};
component.emit = emit.bind(null, component);
return component;
Expand Down Expand Up @@ -431,6 +434,17 @@ function createAppAPI(render) {
};
}

function shouldUpdateComponent(prevVNode, nextVNode) {
const { props: prevProps } = prevVNode;
const { props: nextProps } = nextVNode;
for (const key in prevProps) {
if (prevProps[key] !== nextProps[key]) {
return true;
}
}
return false;
}

function createRenderer(options) {
const { createElement: hostCreateElement, patchProp: hostPatchProp, insert: hostInsert, remove: hostRemove, setElementText: hostSetElementText, } = options;
function render(vnode, container) {
Expand Down Expand Up @@ -463,17 +477,22 @@ function createRenderer(options) {
}
}
function processComponent(n1, n2, container, parentComponent, anchor) {
mountComponent(n2, container, parentComponent, anchor);
if (!n1) {
mountComponent(n2, container, parentComponent, anchor);
}
else {
updateComponent(n1, n2);
}
}
function mountComponent(initialVNode, container, parentComponent, anchor) {
const instance = createComponentInstance(initialVNode, parentComponent);
const instance = (initialVNode.component = createComponentInstance(initialVNode, parentComponent));
setupComponent(instance);
setupRenderEffect(instance, initialVNode, container, anchor);
}
function setupRenderEffect(instance, initialVNode, container, anchor) {
effect(() => {
instance.update = effect(() => {
if (!instance.isMounted) {
// console.log("init")
console.log("init");
const { proxy } = instance;
const subTree = (instance.subTree = instance.render.call(proxy));
patch(null, subTree, container, instance, anchor);
Expand All @@ -482,7 +501,12 @@ function createRenderer(options) {
instance.isMounted = true;
}
else {
// console.log("update")
console.log("update");
const { next, vnode } = instance;
if (next) {
next.el = vnode.el;
updateComponentPreRender(instance, next);
}
const { proxy } = instance;
const subTree = instance.render.call(proxy);
const prevSubTree = instance.subTree;
Expand Down Expand Up @@ -555,8 +579,21 @@ function createRenderer(options) {
});
}
function processFragment(n1, n2, container, parentComponent, anchor) {
// 组件初始
mountChildren(n2.children, container, parentComponent, anchor);
}
// 更新组件
function updateComponent(n1, n2) {
const instance = (n2.component = n1.component);
if (shouldUpdateComponent(n1, n2)) {
instance.next = n2;
instance.update();
}
else {
n2.el = n1.el;
instance.vnode = n2;
}
}
function processText(n1, n2, container) {
const { children } = n2;
const textNode = (n2.el = document.createTextNode(children));
Expand Down Expand Up @@ -724,6 +761,11 @@ function createRenderer(options) {
createApp: createAppAPI(render),
};
}
function updateComponentPreRender(instance, nextVNode) {
instance.vnode = nextVNode;
instance.next = null;
instance.props = nextVNode.props;
}
function getSequence(arr) {
const p = arr.slice();
const result = [0];
Expand Down
52 changes: 47 additions & 5 deletions lib/guide-mini-vue.esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ function createVNode(type, props, children) {
type,
props,
children,
component: null,
key: props && props.key,
shapeFlag: getShapeFlag(type),
el: null,
Expand Down Expand Up @@ -290,6 +291,7 @@ function initProps(instance, rawProps) {
const publicPropertiesMap = {
$el: (i) => i.vnode.el,
$slots: (i) => i.slots,
$props: (i) => i.props,
};
const PublicInstanceProxyHandlers = {
get({ _: instance }, key) {
Expand Down Expand Up @@ -340,6 +342,7 @@ function createComponentInstance(vnode, parent) {
isMounted: false,
subTree: {},
emit: () => { },
next: null,
};
component.emit = emit.bind(null, component);
return component;
Expand Down Expand Up @@ -427,6 +430,17 @@ function createAppAPI(render) {
};
}

function shouldUpdateComponent(prevVNode, nextVNode) {
const { props: prevProps } = prevVNode;
const { props: nextProps } = nextVNode;
for (const key in prevProps) {
if (prevProps[key] !== nextProps[key]) {
return true;
}
}
return false;
}

function createRenderer(options) {
const { createElement: hostCreateElement, patchProp: hostPatchProp, insert: hostInsert, remove: hostRemove, setElementText: hostSetElementText, } = options;
function render(vnode, container) {
Expand Down Expand Up @@ -459,17 +473,22 @@ function createRenderer(options) {
}
}
function processComponent(n1, n2, container, parentComponent, anchor) {
mountComponent(n2, container, parentComponent, anchor);
if (!n1) {
mountComponent(n2, container, parentComponent, anchor);
}
else {
updateComponent(n1, n2);
}
}
function mountComponent(initialVNode, container, parentComponent, anchor) {
const instance = createComponentInstance(initialVNode, parentComponent);
const instance = (initialVNode.component = createComponentInstance(initialVNode, parentComponent));
setupComponent(instance);
setupRenderEffect(instance, initialVNode, container, anchor);
}
function setupRenderEffect(instance, initialVNode, container, anchor) {
effect(() => {
instance.update = effect(() => {
if (!instance.isMounted) {
// console.log("init")
console.log("init");
const { proxy } = instance;
const subTree = (instance.subTree = instance.render.call(proxy));
patch(null, subTree, container, instance, anchor);
Expand All @@ -478,7 +497,12 @@ function createRenderer(options) {
instance.isMounted = true;
}
else {
// console.log("update")
console.log("update");
const { next, vnode } = instance;
if (next) {
next.el = vnode.el;
updateComponentPreRender(instance, next);
}
const { proxy } = instance;
const subTree = instance.render.call(proxy);
const prevSubTree = instance.subTree;
Expand Down Expand Up @@ -551,8 +575,21 @@ function createRenderer(options) {
});
}
function processFragment(n1, n2, container, parentComponent, anchor) {
// 组件初始
mountChildren(n2.children, container, parentComponent, anchor);
}
// 更新组件
function updateComponent(n1, n2) {
const instance = (n2.component = n1.component);
if (shouldUpdateComponent(n1, n2)) {
instance.next = n2;
instance.update();
}
else {
n2.el = n1.el;
instance.vnode = n2;
}
}
function processText(n1, n2, container) {
const { children } = n2;
const textNode = (n2.el = document.createTextNode(children));
Expand Down Expand Up @@ -720,6 +757,11 @@ function createRenderer(options) {
createApp: createAppAPI(render),
};
}
function updateComponentPreRender(instance, nextVNode) {
instance.vnode = nextVNode;
instance.next = null;
instance.props = nextVNode.props;
}
function getSequence(arr) {
const p = arr.slice();
const result = [0];
Expand Down
1 change: 1 addition & 0 deletions src/runtime-core/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function createComponentInstance(vnode, parent) {
isMounted: false,
subTree: {},
emit: () => {},
next: null,
}
component.emit = emit.bind(null, component) as any
return component
Expand Down
1 change: 1 addition & 0 deletions src/runtime-core/componentPublicInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { hasOwn } from "../shared/index"
const publicPropertiesMap = {
$el: (i) => i.vnode.el,
$slots: (i) => i.slots,
$props: (i) => i.props,
}

export const PublicInstanceProxyHandlers = {
Expand Down
Loading

0 comments on commit 496b02a

Please sign in to comment.