Skip to content

Commit f7bb416

Browse files
committed
v.5.0.0 contd
* optimize morphing keyed nodes plus update when only order change for array of keyed nodes * components use data property instead of props property * update examples/tests/benchmarks * update readme
1 parent cbe0b98 commit f7bb416

15 files changed

Lines changed: 411 additions & 409 deletions

README.md

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ It knows **where**, **when** and **what** needs to be rendered.
99

1010
![ModelView](/modelview.jpg)
1111

12-
**Version 5.0.0** (91 kB minified, 28 kB gzipped)
12+
**Version 5.0.0** (93 kB minified, 29 kB gzipped)
1313

1414

1515
**see also:**
@@ -220,7 +220,7 @@ ModelView uses some heuristics in order to morph the real DOM as fast as posible
220220

221221
An example:
222222

223-
```javascript
223+
```html
224224
<div>{
225225
someCondition ? (<ul><li>{text}</li><li>some static text</li></ul>) : (<ul><li>{text2}</li><li>some other static text</li></ul>)
226226
}</div>
@@ -230,7 +230,7 @@ If you run above example and change the value of `someCondition` you will see th
230230

231231
**1st way: make code manifestly dynamic**
232232

233-
```javascript
233+
```html
234234
<div>{
235235
someCondition ? (<ul><li>{text}</li><li>{'some static text'}</li></ul>) : (<ul><li>{text2}</li><li>{'some other static text'}</li></ul>)
236236
}</div>
@@ -240,7 +240,7 @@ In this case we make the different implicitly dynamic but manifestly static part
240240

241241
**2nd way: associate different modelview keys**
242242

243-
```javascript
243+
```html
244244
<div>{
245245
someCondition ? (<ul mv-id="foo"><li>{text}</li><li>some static text</li></ul>) : (<ul mv-id="bar"><li>{text2}</li><li>some other static text</li></ul>)
246246
}</div>
@@ -250,14 +250,64 @@ In this case we associate different modelview keys (`mv-id="foo"`, `mv-id="bar"`
250250

251251
**3rd way: mark html nodes as single unit to be morphed completely**
252252

253-
```javascript
253+
```html
254254
<div>{
255255
someCondition ? view.unit(<ul><li>{text}</li><li>some static text</li></ul>) : view.unit(<ul><li>{text2}</li><li>some other static text</li></ul>)
256256
}</div>
257257
```
258258

259259
In this case we mark the html nodes to be morphed completely as a single unit (ie `view.unit(..)`), instead of applying heuristics, so we have our expected result. Note that this solution is the more general, but might also be slightly slower in some cases.
260260

261+
ModelView is marking when nodes have actually changed. ModelView will apply changes if it sees some explicit changes in the new DOM. That means that if one simply changes the order of items (eg in an array) without actually changing the items or somehow mark them as changed, ModelView will not update the DOM to the new order. To do otherwise by default would be slow(er) and would slow down even in cases where this is not an issue. ModelView takes another route and lets user specify explicitly where more detailed (and slower) morphing should be applied.
262+
263+
An example:
264+
265+
```html
266+
<ul>{
267+
view.model().get('list').map(item => (<li>{item.text}</li>))
268+
}</ul>
269+
```
270+
```javascript
271+
view.model.get('list').sort((a,b) => 0.5 - Math.random()); // create a random order
272+
view.model().notify('list'); // it will not update the order if actual nodes haven't changed
273+
```
274+
275+
276+
However there are two very simple ways to remedy the situation:
277+
278+
279+
**1st way: use keyed nodes**
280+
281+
```html
282+
<ul>{
283+
view.keyed(view.model().get('list').map(item => (<li mv-id={item.id}>{item.text}</li>)))
284+
}</ul>
285+
```
286+
```javascript
287+
view.model.get('list').sort((a,b) => 0.5 - Math.random()); // create a random order
288+
view.model().notify('list'); // updates correctly
289+
```
290+
291+
In this case we use keyed nodes (`mv-id` special property) plus we mark `ul` as having keyed nodes via `view.keyed(..)` method. Having done this, another morphing routine handles changes, which will update to the correct order of items, even if no other changes are made to the individual items. In general it is good practice to use keyed nodes unless having specific reasons not to. In fact many popular frameworks work only with keyed nodes.
292+
293+
294+
**2nd way: use a Model.Collection (with or without keys)**
295+
296+
```javascript
297+
view.model().set('list', new ModelView.Model.Collection(itemsArray));
298+
```
299+
```html
300+
<ul>{
301+
view.model().get('list').mapTo(item => (<li>{item.text}</li>))
302+
}</ul>
303+
```
304+
```javascript
305+
view.model.get('list').sort((a,b) => 0.5 - Math.random()); // create a random order
306+
view.model().notify('list'); // updates correctly
307+
```
308+
309+
In this case `list` is a **Model.Collection**. Collection keeps note of what array operations are performed and mirrors those as DOM operations resulting in very efficient update code in general. So now order will update correctly even if no other changes are made to the individual items (see documentation for details).
310+
261311

262312
ModelView idea and implementation was based on some requirements. One of those is the ability of other actors to manipulate the DOM except ModelView itself. This was a desired feature. **ModelView does not claim exclusive manipulation of the DOM** (unlike frameworks like React or Vue or Inferno), other actors can manipulate the DOM and ModelView will still work (at least in most cases of interest). This is because ModelView relies on the **actual DOM** which is the **only reliable source of truth**. Additionally ModelView provides some necessary direct DOM-level manipulation methods (eg to handle some things even faster, like add/move/remove nodes directly) which can be used along with ModelView's general DOM morphing functionality.
263313

build/modelview.bundle.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)