react hooks in omi

This commit is contained in:
张磊 2018-10-31 17:09:31 +08:00
parent 360aaafbe8
commit 0eaba2d00c
4 changed files with 105 additions and 55 deletions

View File

@ -700,17 +700,17 @@
will emit
{op: replace, path: '/arr/1', value: arr_2}
{op: remove, path: '/arr/2'}
by default, the second operation would revoke the proxy, and this renders arr revoked.
by default, the second operation would revoke the proxy, and this renders arr revoked.
That's why we need to remember the proxies that are inherited.
*/
var revokableInstance = instance.proxifiedObjectsMap.get(newValue);
/*
Why do we need to check instance.isProxifyingTreeNow?
We need to make sure we mark revokables as inherited ONLY when we're observing,
We need to make sure we mark revokables as inherited ONLY when we're observing,
because throughout the first proxification, a sub-object is proxified and then assigned to
its parent object. This assignment of a pre-proxified object can fool us into thinking
that it's a proxified object moved around, while in fact it's the first assignment ever.
Checking isProxifyingTreeNow ensures this is not happening in the first proxification,
Checking isProxifyingTreeNow ensures this is not happening in the first proxification,
but in fact is is a proxified object moved around the tree
*/
if (revokableInstance && !instance.isProxifyingTreeNow) {
@ -787,7 +787,7 @@
this is an inherited proxy (an already proxified object that was moved around),
we shouldn't revoke it, because even though it was removed from path1, it is still used in path2.
And we know that because we mark moved proxies with `inherited` flag when we move them
it is a good idea to remove this flag if we come across it here, in deleteProperty trap.
it is a good idea to remove this flag if we come across it here, in deleteProperty trap.
We DO want to revoke the proxy if it was removed again.
*/
revokableProxyInstance.inherited = false;
@ -1261,29 +1261,37 @@
return ctor.call(this);
};
Element.prototype.useData = function useData(value) {
Element.prototype.beforeRender = function beforeRender() {
this._useId = 0;
};
Element.prototype.use = function use(option) {
var _this2 = this;
this._useId++;
var updater = function updater(newValue) {
_this2._useMap[_this2._useId] = newValue;
var item = _this2._useMap[updater.id];
item.data = newValue;
_this2.update();
_this2._effectFn();
item.effect && item.effect();
};
updater.id = this._useId;
if (!this._isInstalled) {
return [value, updater];
this._useMap[this._useId] = option;
return [option.data, updater];
}
return [this._useMap[this._useId++], updater];
return [this._useMap[this._useId].data, updater];
};
Element.prototype.installed = function installed() {
this._isInstalled = true;
};
Element.prototype.useEffect = function useEffect(fn) {
this._effectFn = fn;
};
return Element;
}(WeElement);
@ -1335,30 +1343,11 @@
});
}
var FUNCTION = 'function';
function tag(name, pure) {
if (typeof pure === FUNCTION) {
var CustomElement = function CustomElement() {
return Reflect.construct(WeElement, [], CustomElement);
};
if (window.Reflect === undefined) {
throw 'Do not use pure element in browsers that do not support Reflect.';
}
CustomElement.pure = true;
CustomElement.prototype.render = pure;
Object.setPrototypeOf(CustomElement.prototype, WeElement.prototype);
Object.setPrototypeOf(CustomElement, WeElement);
customElements.define(name, CustomElement);
} else {
return function (target) {
target.pure = pure;
define(name, target);
};
}
return function (target) {
target.pure = pure;
define(name, target);
};
}
/**
@ -1396,16 +1385,26 @@
};
options.root.Omi = omi;
options.root.Omi.version = '4.0.13';
options.root.Omi.version = '4.0.14';
define('my-counter', function () {
var _useData = this.useData(0),
count = _useData[0],
setCount = _useData[1];
var _use = this.use({
data: 0,
effect: function effect() {
document.title = 'The num is ' + this.data + '.';
}
}),
count = _use[0],
setCount = _use[1];
this.useEffect(function () {
document.title = 'The num is ' + count;
});
var _use2 = this.use({
data: [{ text: 'Omi' }],
effect: function effect() {
console.log('The items count is ' + this.data.length + '.');
}
}),
items = _use2[0],
setItems = _use2[1];
return Omi.h(
'div',
@ -1428,6 +1427,31 @@
return setCount(count + 1);
} },
'+'
),
Omi.h(
'ul',
null,
items.map(function (item) {
return Omi.h(
'li',
null,
item.text
);
})
),
Omi.h(
'button',
{ onClick: function onClick() {
return setItems([].concat(items, [{ text: 'new item' }]));
} },
'add'
),
Omi.h(
'button',
{ onClick: function onClick() {
return setItems([]);
} },
'empty'
)
);
});

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,18 @@
import { define, render } from '../../src/omi'
define('my-counter', function() {
const [count, setCount] = this.useData(0)
const [count, setCount] = this.use({
data: 0,
effect: function() {
document.title = `The num is ${this.data}.`
}
})
this.useEffect(() => {
document.title = `The num is ${count}.`
const [items, setItems] = this.use({
data: [{ text: 'Omi' }],
effect: function() {
console.log(`The items count is ${this.data.length}.`)
}
})
return (
@ -12,6 +20,16 @@ define('my-counter', function() {
<button onClick={() => setCount(count - 1)}>-</button>
<span>{count}</span>
<button onClick={() => setCount(count + 1)}>+</button>
<ul>
{items.map(item => {
return <li>{item.text}</li>
})}
</ul>
<button onClick={() => setItems([...items, { text: 'new item' }])}>
add
</button>
<button onClick={() => setItems([])}>empty</button>
</div>
)
})

View File

@ -19,25 +19,33 @@ export function define(name, ctor) {
return ctor.call(this)
}
useData(value) {
beforeRender() {
this._useId = 0
}
use(option) {
this._useId++
const updater = newValue => {
this._useMap[this._useId] = newValue
const item = this._useMap[updater.id]
item.data = newValue
this.update()
this._effectFn()
item.effect && item.effect()
}
updater.id = this._useId
if (!this._isInstalled) {
return [value, updater]
this._useMap[this._useId] = option
return [option.data, updater]
}
return [this._useMap[this._useId++], updater]
return [this._useMap[this._useId].data, updater]
}
installed() {
this._isInstalled = true
}
useEffect(fn) {
this._effectFn = fn
}
}
customElements.define(name, Element)
}