1 | Composi
|
2 | =======
|
3 |
|
4 | Contents
|
5 | --------
|
6 | - [Installation](../README.md)
|
7 | - [JSX](./jsx.md)
|
8 | - [Hyperx](./hyperx.md)
|
9 | - [Hyperscript](./hyperscript.md)
|
10 | - [Functional Components](./functional-components.md)
|
11 | - Mount, Render and Unmount
|
12 | - [mount](#mount)
|
13 | - [Reusing a Mount to Update Later](#Reusing-a-Mount-to-Update-Later)
|
14 | - [Hydration](#Hydration)
|
15 | - [render](#render)
|
16 | - [How to Use Render](#How-to-Use-Render)
|
17 | - [Unmount](#unmount)
|
18 | - [Remount an Unmounted Functional Component](#Remount-an-Unmounted-Functional-Component)
|
19 | - [Summary](#Summary)
|
20 | - [Components](./components.md)
|
21 | - [State](./state.md)
|
22 | - [Lifecycle Methods](./lifecycle.md)
|
23 | - [Events](./events.md)
|
24 | - [Styles](./styles.md)
|
25 | - [Unmount](./unmount.md)
|
26 | - [State Management with DataStore](./data-store.md)
|
27 | - [Third Party Libraries](./third-party.md)
|
28 | - [Deployment](./deployment.md)
|
29 | - [Differrences with React](./composi-react.md)
|
30 |
|
31 | ## mount
|
32 |
|
33 | This function is used to inject a function component into the DOM. It takes two arguments: the tag to convert to nodes and the element in which to inject the tag. The container can be indicated with a valid CSS selector, or an actualy DOM node. The `mount` function always returns a reference to the element injected into the DOM. You can use this as an argument to the `render` function so that it can update the already mounted component.
|
34 |
|
35 |
|
36 | Here is an example of using `mount`:
|
37 |
|
38 | ```javascript
|
39 | import {h, mount} from 'composi'
|
40 |
|
41 | // Define a functional component:
|
42 | function Header({message}) {
|
43 | return (
|
44 | <nav>
|
45 | <h1>{message}</h1>
|
46 | </nav>
|
47 | )
|
48 | }
|
49 |
|
50 | // Mount the functional component in the document's header element:
|
51 | mount(<Header message="Hello, World!" />, "header")
|
52 | ```
|
53 |
|
54 | ## Reusing a Mount to Update Later
|
55 |
|
56 | The `mount` function returns a virtual node representing the current state of the functional component. You can capture that virtual node in a variable and pass it to the [render](#render) function to update it.
|
57 |
|
58 | ## Hydration
|
59 |
|
60 |
|
61 | You can hydrate content rendered service-side, embuing it with Composi functionality. To do so, just provide a third argument to the `mount` function for the element in the DOM you wish to hydrate. This must be a node reference or a valid selector. Be aware that a selector should indicate a unique element in the document, otherwise it will choose the first occurence in the document.
|
62 |
|
63 | Hydration creates a virtual node from the target element and uses this to patch the DOM with the functional component. This allows Composi to add events and dynamic functionality to server-rendered DOM elements.
|
64 |
|
65 | Suppose we had a list rendered on the server like this:
|
66 |
|
67 | ```html
|
68 | <ul class='list'>
|
69 | <li>Apples</li>
|
70 | <li>Oranges</li>
|
71 | </ul>
|
72 | ```
|
73 | And when it loads we want to update it as a component. We'll define the component and then mount it while also passing a reference to this list:
|
74 |
|
75 | ```javascript import { h, mount } from 'composi'
|
76 | function List(props) {
|
77 | return (
|
78 | <ul class='list'>
|
79 | {
|
80 | props.data.map(item => <li key={item.key}>{item.value}</li>)
|
81 | }
|
82 | </ul>
|
83 | )
|
84 | }
|
85 | // We pass a third argument with a selector for the server-renered list:
|
86 | mount(<List data={fruits}/> 'section', './list')
|
87 | ```
|
88 |
|
89 |
|
90 | ## render
|
91 |
|
92 | Functional components let you create components that are simple yet powerful. The `mount` function makes it easy to inject them into the DOM. But many times you may need to update the component when props or data change. For that you use the `render` function. To use it, you will need to import it into your code:
|
93 |
|
94 | ```javascript
|
95 | import {h, mount, render} from 'composi'
|
96 |
|
97 | ```
|
98 | `render` takes three parameters:
|
99 |
|
100 | 1. vnode - the vnode returned by the mount function
|
101 | 2. tag - the element to create and insert into the DOM
|
102 | 3. container - the element in which the component is mounted
|
103 |
|
104 | When rendering a functional component, always capture the latest vnode node in the varable you used when you mounted it. This gets passed as the first argument, followed by the tag to use to update the component. Although the tag might look exactly like the tag you used to mount, the values of its props can be different depending on events or interactions with the component. Please note that because the component reference from mounting will get reassigned with each render, you must use `let`, not `const` or you will get an error.
|
105 |
|
106 |
|
107 | ## How to Use Render
|
108 |
|
109 | ```javascript
|
110 | import {h, mount, render} from 'composi'
|
111 |
|
112 | const fruits = ['Apples', 'Oranges', 'Bananas']
|
113 |
|
114 | // Define function that returns JSX:
|
115 | function createList({fruits}) {
|
116 | return (
|
117 | <div>
|
118 | <p>
|
119 | <input type='text'/>
|
120 | <button>Add</button>
|
121 | </p>
|
122 | <ul>
|
123 | {
|
124 | fruits.map(fruit => <li>{fruit}</li>)
|
125 | }
|
126 | </ul>
|
127 | </div>
|
128 | )
|
129 | }
|
130 |
|
131 | // Insert the list into the document body:
|
132 | const list = mount(<List fruits={fruits}/>, 'body')
|
133 |
|
134 | // Define event object:
|
135 | const listEvents = {
|
136 | // Define event handler:
|
137 | handleEvent(e) {
|
138 | e.target.nodeName === 'BUTTON' && this.addItem()
|
139 | },
|
140 | // Store reference to form input:
|
141 | input : document.querySelector('input')
|
142 | // Define method to add item and update list:
|
143 | addItem() {
|
144 | const value = this.document.value
|
145 | if (value) {
|
146 | fruits.push(value)
|
147 | // Update the list component with "render".
|
148 | // Capture the latest vnode version of the component in the variable used to mount.
|
149 | // This will get passed in on the next render.
|
150 | list = render(list, <List fruits={fruits}/>, 'body')
|
151 | // Clear input value:
|
152 | input.value = ''
|
153 | } else {
|
154 | alert('Please provide a value before submitting.')
|
155 | }
|
156 | }
|
157 | }
|
158 | ```
|
159 |
|
160 | In the above example, each subsequent call of the `render` function will update the DOM tree structure with new data. Technically, if we wanted to modify the order of the list items, we would want to render them with a key.
|
161 |
|
162 | ## unmount
|
163 |
|
164 | The `unmount` function lets you remove a mounted functional component from the DOM. To do so you pass it the reference to the functional component that was returned by the `mount` function:
|
165 |
|
166 | ```javascript
|
167 | function Title({message}) {
|
168 | return (
|
169 | <nav>
|
170 | <h1>Hello, {message}!</h1>
|
171 | </nav>
|
172 | )
|
173 | }
|
174 | let title = mount(<Title message='World'/>, 'header')
|
175 |
|
176 | // Unmount the title after 5 seconds:
|
177 | setTimeout(() => unmount(title), 5000)
|
178 | ```
|
179 |
|
180 | In most cases using conditional logic to render a functional component makes more sense. However, if conditional logic is not feasable or adds too much complexity to a component, you can use `unmount` to remove the mounted functional component from the DOM.
|
181 |
|
182 | ## Remount an Unmounted Functional Component
|
183 |
|
184 | After you've unmounted a functional component, you can remount it later using the `mount` function:
|
185 |
|
186 | ```javascript
|
187 | function Title({message}) {
|
188 | return (
|
189 | <nav>
|
190 | <h1>Hello, {message}!</h1>
|
191 | </nav>
|
192 | )
|
193 | }
|
194 | let title = mount(<Title message='World'/>, 'header')
|
195 |
|
196 | // Unmount the title after 5 seconds:
|
197 | setTimeout(() => unmount(title), 5000)
|
198 |
|
199 | // Remount the title 5 seconds after it was unmounted:
|
200 | setTimeout() => {
|
201 | title = mount(<Title message='World'/>, 'header')
|
202 | }, 10000)
|
203 | ```
|
204 |
|
205 | ## Summary
|
206 |
|
207 | Both `mount` and `render` are similar in purpose to [`ReactDOM.render`](https://facebook.github.io/react/docs/react-dom.html#render). The main difference is that Composi separates mounting from updating. These means the two function have difference arguments. `mount` expects a second argument for where to inject the component, whereas `render` expects a second argument of the DOM tree to update. If your components need local state, class components might be a better choice. Or not. It depends on your specific needs and your design choices. If you do not like ES6 classes, you can stick with just `mount` and `render` for creating functional components. If your components are very complex, class components may solve your problems better and result in better organization of responsibilities and concerns. |
\ | No newline at end of file |