UNPKG

11.6 kBMarkdownView Raw
1Composi
2=======
3
4Contents
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](./render.md)
12- [Components](./components.md)
13- [State](./state.md)
14- [Lifecycle Methods](./lifecycle.md)
15- [Events](./events.md)
16- [Styles](./styles.md)
17- [Unmount](./unmount.md)
18- [State Management with DataStore](./data-store.md)
19- [Third Party Libraries](./third-party.md)
20- [Deployment](./deployment.md)
21- Differences with React
22 - [Differences Between Composi and React](#Differences-Between-Composi-and-React)
23 - [API](#API)
24 - [Properties](#Properties)
25 - [Lifecycle Hooks for Class Components](#Lifecycle-Hooks-for-Class-Components)
26 - [Lifecycle Events for Functional Components](#Lifecycle-Events-for-Functional-Components)
27 - [createRef/Ref](#createRef/Ref)
28 - [Instantiation](#Instantiation)
29
30## Differences Between Composi and React
31
32Although Composi and React share many API features, there are substantial differences. The following tables show what they share and how they differ.
33
34## API
35
36| Composi | React |
37|--------------------|-----------------------------|
38| h | React.createElement |
39| mount | ReactDOM.hydrate |
40| render | ReactDOM.render |
41| Component | React.Component |
42| Component.render | React.Component.render |
43| Component.state | React.Component.state |
44| Component.setState | React.Component.setState |
45| Component.update | React.Component.forceUpdate |
46| Component.unmount | N/A |
47| Fragment | React.Fragment |
48
49Composi uses `mount` to render a functional component the first time. This returns a reference to the component tree. You can pass that reference to the `render` function in order to update that functional component efficiently. Only that tree will be updated.
50
51`mount` is also used to hydrate server-side rendered DOM with functional components, similar to `ReactDOM.hydrate`. Just pass a DOM reference for the structure to hydrate as the third argument to `mount`:
52
53```javascript
54// Hydrate H1 inside header tag:
55mount(<Title message='Amazing Title'/> 'header', 'h1')
56```
57If you wish to update a component after mounting, capture its state in a variable. You'll need to use `let` because each update will change the value you have stored.
58
59```javascript
60// Hydrate H1 inside header tag:
61let title = mount(<Title message='Amazing Title'/> 'header', 'h1')
62```
63
64Use `render` to update an already mounted functional component. It takes three arguments, a reference to the mounted component and the tag to re-render and the container element to render it in. This will be the same one in which the component was originally mounted:
65
66```javascript
67let title = mount(<Title message='Boring!'/>, 'header')
68// Sometime later update the title.
69// Pass in the 'title' variable from above:
70title = render(title, <Title message='An Amazing Title!!!'/>, 'header')
71```
72
73## Properties
74
75| Composi | React |
76|----------------------------------|----------------------------------------------|
77| class | className |
78| inline events | inline events (synthesized) |
79| onclick | onClick |
80| oninput | onUpdate |
81| for | htmlFor |
82| xlink-href | xlinkHref or xlink-href |
83| innerHTML (string) | dangerouslySetInnerHTML (callback) |
84| style (accepts object or | |
85| standard inline string value) | style (accepts object) |
86
87Inline events are just inline events, same as they've always been since DOM Level 0. Composi uses standard HTML attributes. No need for camel case or non-standard terms. For SVG icons you can use `xlink-href`. `innerHTML` accepts a string as its value. No need for a complicated function like with React's `dangerouslySetInnerHTML`. `style` can take a JavaScript object literal of key value pairs, or you can use a string as you normally would with HTML. React and friends only accept an object.
88
89For handling `innerHTML`, Composi uses `innerHTML`. Unlike React, which requires a callback, you just pass a string for the content to insert:
90
91```javascript
92function Title() {
93 return (
94 <h1>Original Content</h1>
95 )
96}
97const title = mount(<Title/>, 'header')
98// Later update the title:
99title = render(title, <Title innerHTML='The New Title!'/>, 'header')
100```
101
102## Lifecycle Hooks for Class Components
103
104| Composi | React |
105|---------------------------|------------------------------------------------------------|
106| componentWillMount | componentWillMount/UNSAFE_componentWillMount |
107| componentDidMount | comopnentDidMount |
108| componentWillUpdate | componentWillUpdate/UNSAFE_componentWillUpdate |
109| componentDidUpdate | componentDidUpdate |
110| componentWillUnmount | componentWillUnmount/UNSAFE_componentWillUnmount |
111| N/A | componentWillReceiveProps/UNSAFE_componentWillReceiveProps |
112| N/A | getDerivedStateFromProps |
113| componentShouldUpdate (attribute) | componentShouldUpdate (callback) |
114
115
116## Lifecycle Events for Functional Components
117
118| Composi | React |
119|-----------------|------------|
120| onmount | N/A |
121| onupdate | N/A |
122| onunmount | N/A |
123
124Inline events are standard inline events. They do not get sythesized like React.
125
126`componentShouldUpdate` is an attribute that accepts a boolean value. By default it is true. Setting this property to false will prevent it from updating, event when its state changes. After making state changes, you can flag the component to update again by setting this property to true. The next update will show the changes.
127
128```javascript
129class Title extends Component {
130 render(data) {
131 return (
132 <h1>{data}</h1>
133 )
134 }
135}
136// Create instance.
137// Because it has no state, it does not yet render.
138const title = new Title({
139 state: 'A Great Title',
140 container: 'header'
141})
142title.componentShouldUpdate = false
143
144// Sometime later you want to change the title.
145// Because 'componentShouldUpdate' was set to false, nothing will happen.
146title.setState('A Brand New Title!')
147
148// To update the component, set 'componentShouldUpdate' to true,
149// then run 'update' on the component instance:
150title.componentShouldUpdate = true
151title.update()
152```
153
154## createRef/Ref
155
156| Composi | React |
157|-------------------------------------------------|-----------------|
158| N/A (use this.element with componentDidMount | |
159| to access DOM) | React.createRef |
160| N/A (same as above) | ref |
161
162Composi does not have `createRef` like React, and so it does not support the `ref` property on elements. But you don't need it. Instead you can take advantage of a component's `element` property in the `componentDidUpdate` lifecycle hook to access elements in the DOM:
163
164```javascript
165class List extends Component {
166 render(data) {
167 return (
168 <div class='list-container'>
169 <p>
170 <input type='text'/>
171 <button>Add</button>
172 </p>
173 <ul>
174 {
175 data.map(item => <li key={item.key}>{item.value}</li>)
176 }
177 </ul>
178 </div>
179 )
180 }
181 componentDidMount() {
182 // Notice how we access the component tree here:
183 this.element.querySelector('button').addEventListener('click', this)
184 this.input = this.element.querySelector('input')
185 }
186 handleEvent() {
187 this.addItem()
188 }
189 addItem() {
190 // Access input that we got in componentDidMount:
191 const value = this.input.value
192 if (value) {
193 this.setState(prevState => {
194 prevState.push(value)
195 return prevState
196 })
197 } else {
198 alert('Please provide a value before submitting.')
199 }
200 }
201}
202```
203
204## Instantiation
205
206| Composi | React |
207|-----------------------------------------|----------------------------------|
208| mount (for functional components) | ReactDOM.hydrate/ReactDOM.render |
209| new - use to instatiate class component | React.DOM.render
210
211To render a functional component the first time, use `mount`:
212
213```javascript
214function Title({message}) {
215 return (
216 <nav>
217 <h1>{message}</h1>
218 </nav>
219 )
220}
221// Mount the custom tag in the header:
222const title = mount(<Title message='A Great Title'/>, 'header')
223```
224
225To mount a class component, instantiate it with the `new` keyword. If the class component has state, it will render to the DOM automatically when you instantiate it. If it is stateless, you'll need to run `update` on the instance to render it.
226
227```javascript
228//Stateful component:
229class Title extends Component {
230 state = 'A Great Title'
231 render(message) {
232 return (
233 <nav>
234 <h1>{message}</h1>
235 </nav>
236 )
237 }
238}
239
240// Create instance of component.
241// Indicate where to render through container property.
242// Because it has state, the component will immediately render to the DOM:
243const title = new Title({
244 container: 'header'
245})
246
247// Or you could provide state while initalizing.
248// Here we refactor the above class for that:
249
250//Stateless component:
251class Title extends Component {
252 render(message) {
253 return (
254 <nav>
255 <h1>{message}</h1>
256 </nav>
257 )
258 }
259}
260
261// Create instance of component.
262// Provide state for the component to use.
263// Indicate where to render through container property.
264// Because we provide state here, the component will render immediately.
265const title = new Title({
266 state: 'A Great Title',
267 container: 'header'
268})
269
270// We could also define a stateless component and add state after instantiation. This will also cause the stateless component to render immediately. Here we take the previous stateless component to illustrate this:
271
272//Stateless component:
273class Title extends Component {
274 render(message) {
275 return (
276 <nav>
277 <h1>{message}</h1>
278 </nav>
279 )
280 }
281}
282
283// Because this has no state, instantiation will not cause it to render to the DOM yet.
284const title = new Title({
285 container: 'header'
286})
287
288// Provide state to the component instance.
289// This will cause it to render immediately.
290title.state = 'A Great Title'
291
292// Finally, we can keep the component stateless and use the `update` function to pass data. This will render the component to the DOM using the data we provide.
293
294//Stateless component:
295class Title extends Component {
296 render(message) {
297 return (
298 <nav>
299 <h1>{message}</h1>
300 </nav>
301 )
302 }
303}
304
305// Because this has no state, instantiation will not cause it to render to the DOM yet.
306const title = new Title({
307 container: 'header'
308})
309
310// Pass data to the stateless component, causing it to render immediately.
311title.update('A Great Title')
312```
\No newline at end of file