Merge remote-tracking branch 'origin/rewrite' into rewrite
This commit is contained in:
commit
7f8363560e
18 changed files with 289 additions and 69 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
- [API](#api)
|
||||
- [How it works](#how-it-works)
|
||||
- [Performance considerations](#performance-considerations)
|
||||
- [Differences from m.render](#differences-from-m-render)
|
||||
|
||||
---
|
||||
|
|
@ -13,7 +14,7 @@
|
|||
Argument | Type | Required | Description
|
||||
----------- | -------------------- | -------- | ---
|
||||
`element` | `Element` | Yes | A DOM element that will be the parent node to the subtree
|
||||
`component` | `Component` | Yes | The [component](components.md) to be rendered
|
||||
`component` | `Component|null` | Yes | The [component](components.md) to be rendered. `null` unmounts the tree and cleans up internal state.
|
||||
**returns** | | | Returns nothing
|
||||
|
||||
[How to read signatures](signatures.md)
|
||||
|
|
@ -24,6 +25,18 @@ Argument | Type | Required | Description
|
|||
|
||||
Similar to [`m.render()`](render.md), the `m.mount()` method takes a component and mounts a corresponding DOM tree into `element`. If `element` already has a DOM tree mounted via a previous `m.mount()` call, the component is diffed against the previous vnode tree and the existing DOM tree is modified only where needed to reflect the changes. Unchanged DOM nodes are not touched at all.
|
||||
|
||||
#### Replace a component
|
||||
|
||||
Running `mount(element, OtherComponent)` where `element` is a current mount point replaces the component previously mounted with `OtherComponent`.
|
||||
|
||||
#### Unmount
|
||||
|
||||
Using `m.mount(element, null)` on an element with a previously mounted component unmounts it and cleans up Mithril internal state. This can be useful to prevent memory leaks when removing the `root` node manually from the DOM.
|
||||
|
||||
---
|
||||
|
||||
### Performance considerations
|
||||
|
||||
It may seem wasteful to generate a vnode tree on every redraw, but as it turns out, creating and comparing Javascript data structures is surprisingly cheap compared to reading and modifying the DOM.
|
||||
|
||||
Touching the DOM can be extremely expensive for a couple of reasons. Alternating reads and writes can adversely affect performance by causing several browser repaints to occur in quick succession, whereas comparing virtual dom trees allows writes to be batched into a single repaint. Also, the performance characteristics of various DOM operations vary between implementations and can be difficult to learn and optimize for all browsers. For example, in some implementations, reading `childNodes.length` has a complexity of O(n); in some, reading `parentNode` causes a repaint, etc.
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ In contrast, traversing a javascript data structure has a much more predictable
|
|||
|
||||
### Differences from other API methods
|
||||
|
||||
`m.render()` method is internally called by [`m.mount()`](mount.md), [`m.route()`](route.md), [`m.redraw()`](redraw.md) and `[m.request()](request.md)`. It is not called by [`m.prop()`](prop.md)
|
||||
`m.render()` method is internally called by [`m.mount()`](mount.md), [`m.route()`](route.md), [`m.redraw()`](redraw.md) and [`m.request()`](request.md). It is not called by [`m.prop()`](prop.md)
|
||||
|
||||
Unlike with `m.mount()` and `m.route()`, a vnode tree rendered via `m.render()` does not auto-redraw in response to view events, `m.redraw()` calls or `m.request()` calls. It is a low level mechanism suitable for library authors who wish to manually control rendering instead of relying on Mithril's built-in auto-redrawing system.
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ Argument | Type | Required | Descript
|
|||
`options.type` | `any = Function(any)` | No | A constructor to be applied to each object in the response. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function).
|
||||
`options.serialize` | `string = Function(any)` | No | A serialization method to be applied to `data`. Defaults to `JSON.stringify`, or if `options.data` is an instance of [`FormData`](https://developer.mozilla.org/en/docs/Web/API/FormData), defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function) (i.e. `function(value) {return value}`).
|
||||
`options.deserialize` | `any = Function(string)` | No | A deserialization method to be applied to the response. Defaults to a small wrapper around `JSON.parse` that returns `null` for empty responses.
|
||||
`options.extract` | `string = Function(xhr, options)` | No | A hook to specify how the XMLHttpRequest response should be read. Useful for reading response headers and cookies. Defaults to a function that returns `xhr.responseText`
|
||||
`options.extract` | `string = Function(xhr, options)` | No | A hook to specify how the XMLHttpRequest response should be read. Useful for reading response headers and cookies. Defaults to a function that returns `xhr.responseText`. If defined, `options.deserialize` is ignored.
|
||||
`options.initialValue` | `any` | No | A value to populate the returned stream before the request completes
|
||||
`options.useBody` | `Boolean` | No | Force the use of the HTTP body section for `data` in `GET` requests when set to `true`, or the use of querystring for other HTTP methods when set to `false`. Defaults to `false` for `GET` requests and `true` for other methods.
|
||||
**returns** | `Stream` | | A stream that resolves to the response data, after it has been piped through the `extract`, `deserialize` and `type` methods
|
||||
|
|
@ -378,6 +378,26 @@ Ignoring the fact that the parseCSV function above doesn't handle a lot of cases
|
|||
|
||||
---
|
||||
|
||||
|
||||
### Retrieving response details
|
||||
|
||||
By default Mithril attempts to parse a response as JSON and returns `xhr.responseText`. It may be useful to inspect a server response in more detail, this can be accomplished by passing a custom `options.extract` function:
|
||||
|
||||
```javascript
|
||||
m.request({
|
||||
method: "GET",
|
||||
url: "/api/v1/users",
|
||||
extract: function(xhr) {return {status: xhr.status, body: xhr.responseText}}
|
||||
})
|
||||
.run(function(response) {
|
||||
console.log(response.status, response.body)
|
||||
})
|
||||
```
|
||||
|
||||
The parameter to `options.extract` is the XMLHttpRequest object once its operation is completed, but before it has been passed to the resulting [stream](prop.md), so the stream may still end up in an errored state if processing throws an exception.
|
||||
|
||||
---
|
||||
|
||||
### Why JSON instead of HTML
|
||||
|
||||
Many server-side frameworks provide a view engine that interpolates database data into a template before serving HTML (on page load or via AJAX) and then employ jQuery to handle user interactions.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
- [Component `controller` function](#component-controller-function)
|
||||
- [Component arguments](#component-arguments)
|
||||
- [Passing components to `m()`](#passing-components-to-m)
|
||||
- [Passing vnodes to `m.mount()` and `m.route()`](#passing-vnodes-to-mmount-and-mroute)
|
||||
- [`m.route` mode](#mroute-mode)
|
||||
- [`m.route` and anchor tags](#mroute-and-anchor-tags)
|
||||
- [Reading/writing the current route](#readingwriting-the-current-route)
|
||||
|
|
@ -178,6 +179,34 @@ m("div", component);
|
|||
m("div", m(component));
|
||||
```
|
||||
|
||||
## Passing vnodes to `m.mount()` and `m.route()`
|
||||
|
||||
In `v0.2.x`, `m.mount(element, component)` tolerated [vnodes](vnodes.md) as second arguments instead of [components](components.md) (even though it wasn't documented). Likewise, `m.route(element, defaultRoute, routes)` accepted vnodes as values in the `routes` object.
|
||||
|
||||
In `v1.x`, components are required instead in both cases.
|
||||
|
||||
### `v0.2.x`
|
||||
|
||||
```javascript
|
||||
m.mount(element, m('i', 'hello'));
|
||||
m.mount(element, m(Component, attrs));
|
||||
|
||||
m.route(element, '/', {
|
||||
'/': m('b', 'bye')
|
||||
})
|
||||
```
|
||||
|
||||
### `v1.x`
|
||||
|
||||
```javascript
|
||||
m.mount(element, {view: function () {return m('i', 'hello')}});
|
||||
m.mount(element, {view: function () {return m(Component, attrs)}});
|
||||
|
||||
m.route(element, '/', {
|
||||
'/': {view: function () {return m('b', 'bye')}}
|
||||
})
|
||||
```
|
||||
|
||||
## `m.route` mode
|
||||
|
||||
`m.route.mode` was replaced by `m.route.prefix(prefix)` where `prefix` can be `#`, `?`, `` (for "pathname" mode). The new API also supports hashbang (`#!`), which is the default, and it supports non-root pathnames and arbitrary mode variations such as querybang (`?!`)
|
||||
|
|
@ -330,3 +359,5 @@ m.prop.merge([
|
|||
console.log("Contributors:", users[0].name, "and", users[1].name);
|
||||
});
|
||||
```
|
||||
|
||||
Additionally, if the `extract` option is passed to `m.request` the return value of the provided function will be passed to the [m.prop stream](prop.md) directly, and any `deserialize` callback is ignored.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue