This repository was archived by the owner on Sep 3, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy paththinking-in-composi.html
453 lines (410 loc) · 29.8 KB
/
thinking-in-composi.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="description" content="Composi is a JavaScript library for creating component-based interfaces. It uses the virtual dom to make efficient updates to the DOM based on a component's data or state.">
<meta name="keywords" content="javascript, framework, performance, small, fast, UI, programming, code, component, composi, chocolatechipui, chocolatechip-ui, reactive, virtual dom">
<title>Composi - Tutorials</title>
<link rel="stylesheet" href="../css/styles.css">
<link rel="stylesheet" href="../css/styles.css">
<link rel="stylesheet" href="../css/prism-tomorrow.css">
</head>
<body class='tutorial-page'>
<nav>
<ul class='nav--menu'>
<li class='nav--menu__item'>
<a class='nav--menu__item__link' href="../index.html">
<svg id='composi-logo' viewBox="0 0 300 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Composi Logo</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Composi-Logo-Solid" fill="#fff">
<path d="M1.77635684e-15,0 L95,0 L95,38 L209,38 L209,0 L300,0 L300,94 L265,93.8571663 L265,209 L300,209 L300,300 L209,300 L209,265 L95,265 L95,300 L1.77635684e-15,300 L1.77635684e-15,209 L40,209 L40,94 L1.77635684e-15,93.8571663 L1.77635684e-15,0 Z M107,107 L107,192 L192,192 L192,107 L107,107 Z" id="Combined-Shape"></path>
</g>
</g>
</svg>
<span class='logo__link--text'>Composi</span></a>
</li>
<li class='nav--menu__item'>
<a class='nav--menu__item__link' href="../docs/installation.html">Docs</a>
</li>
<li class='nav--menu__item selected'>
<a class='nav--menu__item__link' href="./index.html">Tutorials</a>
</li>
<li class='nav--menu__item'>
<a class='nav--menu__item__link external' target='__blank' href="https://github.com/composor/awesome-composi">Resources
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="14px" height="14px" viewBox="0 0 511.626 511.627" style="enable-background:new 0 0 511.626 511.627;"
xml:space="preserve">
<path fill='#fff' d="M392.857,292.354h-18.274c-2.669,0-4.859,0.855-6.563,2.573c-1.718,1.708-2.573,3.897-2.573,6.563v91.361
c0,12.563-4.47,23.315-13.415,32.262c-8.945,8.945-19.701,13.414-32.264,13.414H82.224c-12.562,0-23.317-4.469-32.264-13.414
c-8.945-8.946-13.417-19.698-13.417-32.262V155.31c0-12.562,4.471-23.313,13.417-32.259c8.947-8.947,19.702-13.418,32.264-13.418
h200.994c2.669,0,4.859-0.859,6.57-2.57c1.711-1.713,2.566-3.9,2.566-6.567V82.221c0-2.662-0.855-4.853-2.566-6.563
c-1.711-1.713-3.901-2.568-6.57-2.568H82.224c-22.648,0-42.016,8.042-58.102,24.125C8.042,113.297,0,132.665,0,155.313v237.542
c0,22.647,8.042,42.018,24.123,58.095c16.086,16.084,35.454,24.13,58.102,24.13h237.543c22.647,0,42.017-8.046,58.101-24.13
c16.085-16.077,24.127-35.447,24.127-58.095v-91.358c0-2.669-0.856-4.859-2.574-6.57
C397.709,293.209,395.519,292.354,392.857,292.354z"/>
<path fill='#fff' d="M506.199,41.971c-3.617-3.617-7.905-5.424-12.85-5.424H347.171c-4.948,0-9.233,1.807-12.847,5.424
c-3.617,3.615-5.428,7.898-5.428,12.847s1.811,9.233,5.428,12.85l50.247,50.248L198.424,304.067
c-1.906,1.903-2.856,4.093-2.856,6.563c0,2.479,0.953,4.668,2.856,6.571l32.548,32.544c1.903,1.903,4.093,2.852,6.567,2.852
s4.665-0.948,6.567-2.852l186.148-186.148l50.251,50.248c3.614,3.617,7.898,5.426,12.847,5.426s9.233-1.809,12.851-5.426
c3.617-3.616,5.424-7.898,5.424-12.847V54.818C511.626,49.866,509.813,45.586,506.199,41.971z"/>
</svg></a>
</li>
</ul>
</nav>
<article class='tutorial__article'>
<section>
<div class='tutorial'>
<h1>Thinking in Composi</h1>
<p class="tutorial__intro">Composi is a great tool for creating complex Web apps with JavaScript. It's flexible and versitile, working well with third party libraries and frameworks</p>
<p>Because of its emphasis on components, it forces you to think about the structure of your app as you build it: functional component, class-based component, data flowing down, stateless components or stateful components.</p>
<p>To show how to tackle a project with Composi, we're going to walk through building a spreadsheet from scratch. It's going to be a simple spreadsheet, just so you can see the steps we take to implement it.</p>
<h2>Start With A Mockup</h2>
<p>Always start with a mockup of what it is you want to build. It might be a simple sketch on paper, or a Photoshop file from a graphic design. Work with whatever you have at hand. Don't try to create a mockup of every possible feature. Start with the basic. For our spreadsheet, we're keeping it basic. Here's what we want to build:</p>
<p><img src="../images/spreadsheet-1.png" alt="Basic spreadsheet we want to build."></p>
<h2>Identify the Component Hierarchy</h2>
<p>With the mockup in hand, you need to look at it and analyze the parts that need to be built. The main part will be the parent component that encompases everything in the mockup. After that, there's a spreadsheet component, and another one to add a new row. The best way to identify the parts is to draw color rectangles around them. Notice how we identify parts in the next image:</p>
<p><img src="../images/spreadsheet-3.png" alt="Basic spreadsheet we want to build."></p>
<p>Here's what we see as the the parts based on rectangle colors:</p>
<ul>
<li>Orange: the parent component</li>
<li>Green: a component that adds a new row to the spreadsheet</li>
<li>Blue: a component that implements spreadsheet functionality</li>
<li>Red: a component that creates the table header for the spreadsheet</li>
<li>Violet: a component that creates the individual spreadsheet rows</li>
<li>Yellow: a component that creates the sum of all the spreadsheet cells of price and quantity</li>
</ul>
<p>We can clarify the component hierarchy by representing it as a tree:</p>
<div class='spreadsheet--tree'>
<ul>
<li>SpreadSheetComponent
<ul>
<li>SpreadSheet
<ul>
<li>TableHeader</li>
<li>TableRow</li>
<li>TableFooter</li>
</ul>
</li>
<li>AddNewRow</li>
</ul>
</li>
</ul>
</div>
<p> </p>
<h2>Build a Static Version with Composi</h2>
<p>The best way to started is to create the main component and have it build the static markup for the entire component. Later, based on the hierarchy we established above, we will break it down in separate sub-components and use composition to assemble them together.</p>
<p>First things first, we need the markup. We'll start with the shell. Since it has two main parts, we'll use an unorder list with two list items. We're going to use a bit of <a target='__blank' href='http://getbem.com/introduction/'>BEM</a> for class and to make the styling easier:</p>
<p data-height="300" data-theme-id="6688" data-slug-hash="efcec8e78d141c201d049f6f21691d72" data-default-tab="html,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-1" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/efcec8e78d141c201d049f6f21691d72/">Composi Tuts - Thinking in Composi-1</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<p>The first list item with hold the <code>SpreadSheet</code> component. The second list item will hold <code>AddNewRow</code>. For now, we're going to create the <code>AddNewRow</code> markup, because it's easier:</p>
<p data-height="350" data-theme-id="6688" data-slug-hash="568fb1d069ea25ba2989576a1b34674d" data-default-tab="html,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-2" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/568fb1d069ea25ba2989576a1b34674d/">Composi Tuts - Thinking in Composi-2</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<p>Now let's tackle that spreadsheet. We've got three parts to make: the table header, the table body row and the footer with the sum in it:</p>
<p data-height="450" data-theme-id="6688" data-slug-hash="NwPXWq" data-default-tab="html,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-3" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/NwPXWq/">Composi Tuts - Thinking in Composi-3</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<p>As you can see, we now have basic structure, but no data. We'll need some mock data for the first render and were going with fruits:</p>
<pre><code class="language-javascript">const fruitData = [
{
product: 'Apple',
price: 1.50,
quantity: 5
},
{
product: 'Orange',
price: 1.00,
quantity: 7
},
{
product: 'Banana',
price: .90,
quantity: 3
}, {
product: 'Peach',
price: 1.10,
quantity: 0
}
]</code></pre>
<p> </p>
<h2>Creating A Basic Component</h2>
<p>Time to make the component. We're first going to implement the render function that creates the previous markup, then we'll add in variables to output our mock data. So, without further ado:</p>
<p data-height="500" data-theme-id="6688" data-slug-hash="RjNxrO" data-default-tab="js,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-4" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/RjNxrO/">Composi Tuts - Thinking in Composi-4</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
</pre>
<p>This gives us a functioning component rendering a static shell. We need to update it to use the data, <code>fruitData</code>. Also note, that forth column with the header of "Total" needs to show the total for that row. We'll need to do some math when we render the row to print the total for that row. The total will be the item price times the item qunatity. We can access them as we did in their cells. One last thing, because both price and total represent currency, we what to make sure the numerical value always has a decimal followed by two decimal places. We can do that by using <code>.toFixed(2)</code> on the value.</p>
<p>Here's how we output a spreadsheet row for each data row:</p>
<pre><code class="language-javascript">// Loop over array of fruits,
// printing each row:
{
rows.map(row => (
<tr>
<td>{row.product}</td>
<td>
<!-- Use "toFixed(2)" on price -->
<input class='price' type='number' min='0' value={row.price.toFixed(2)}/>
</td>
<td>
<input class='quantity' type='number' min='0' value={row.quantity}/>
</td>
<td>
<!-- Multiple quantity x price for total and format with "toFixed(2)" -->
<span class='total'>${(row.price * row.quantity).toFixed(2)}</span>
</td>
<td>
<button class='list__item__button--delete'>X</button>
</td>
</tr>
))
}</code></pre>
<p>With this change, our complete component should look like this:</p>
<p data-height="600" data-theme-id="6688" data-slug-hash="0c2d34374c03a67f2e59301d38e3ad4b" data-default-tab="js,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-5" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/0c2d34374c03a67f2e59301d38e3ad4b/">Composi Tuts - Thinking in Composi-5</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
</pre>
<p> </p>
<h2>Add Total Sum</h2>
<p>That footer is missing the total price of all rows. For that we need to add a function and then call it in our footer:</p>
<p data-height="600" data-theme-id="6688" data-slug-hash="0a07dc8c0a6eaf89203412072982b622" data-default-tab="js,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-6" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/0a07dc8c0a6eaf89203412072982b622/">Composi Tuts - Thinking in Composi-6</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<p>This will now ouput the sum of all rows in the footer. Notice that we also added a <code>$</code> right before the sum.</p>
<h2>Add New Row</h2>
<p>Next let's make it so the user can add a new item. We need to be able to capture the item name, as well as its price and quantity. We'll need to provide a defalt value of 0 in case the user doesn't bother providing a price or quantity. When we add the new item, we want the spreadsheet to show it. We also want the sum to reflex the new row's values. That means we need to add the new item to the spreadsheet's state.</p>
<p>Adding a new item will require a user interaction. For that we will need an event on the button to submit the new values. We'll use the <code>handleEvent</code> interface and the <code>componentDidMount</code> hook to set that up. We'll call the new method, <code>addNewRow</code>:</p>
<pre><code class="language-javascript">addNewRow(e) {
// Get the value of the inputs:
const productInput = this.element.querySelector('#product')
const priceInput = this.element.querySelector('#price')
const quantityInput = this.element.querySelector('#quantity')
const product = productInput.value
// Set default values for price and quantity:
const price = Number(priceInput.value) || 0
const quantity = Number(quantityInput.value) || 0
// Set inputs back to empty:
productInput.value = ''
priceInput.value = ''
quantityInput.value = ''
// Check if user entered a product name:
if (product) {
// Update component state with new product:
this.setState(prevState => prevState.push({product, price, quantity}))
} else {
// User hit Add button without entering product:
alert('Please provide a product name before trying to add a row.')
}
}
// And set up an event to capture button click:
componentDidMount() {
this.element.addEventListener('click', this)
}</code></pre>
<p>With this addition, we get:</p>
<p data-height="600" data-theme-id="6688" data-slug-hash="OOPQLW" data-default-tab="js,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-7" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/OOPQLW/">Composi Tuts - Thinking in Composi-7</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<p> </p>
<h2>Updating Price and Quantity</h2>
<p>Next we want to be able to update the price or quantity of a row item. Since those are input tags, we'll also need to add another event listener for type <code>input</code> in our <code>componentDidMount</code> hook. We'll also need two more methods: <code>updatePrice</code> and <code>updateQuantity</code>.</p>
<p>In order to make the rows editable, we need a way to associate each row with the corresponding index of the state array. We can do that by printing the array index on the interactive elements. We'll use the <code>data-index</code> attribute on those elements. Here's our updated code for the table cells. Notice the new attribute <code>data-index</code> on the price input, quantity input and button:</p>
<pre><code class="language-javascript">{
rows.map(row => (
<tr>
<td>{row.product}</td>
<td>
<!-- Use "toFixed(2)" on price -->
<input class='price' data-index={idx} type='number' min='0' value={row.price.toFixed(2)}/>
</td>
<td>
<input class='quantity' data-index={idx} type='number' min='0' value={row.quantity}/>
</td>
<td>
<!-- Multiple quantity x price for total and format with "toFixed(2)" -->
<span class='total'>${(row.price * row.quantity).toFixed(2)}</span>
</td>
<td>
<button data-index={idx} class='list__item__button--delete'>X</button>
</td>
</tr>
))
}</code></pre>
<p>Now we can procede with adding the new methods to update price and quantity to our component:</p>
<pre><code class="language-javascript">updateQuantity(e) {
// Get the array index stored on the input.
// With that we can update the state.
const index = e.target.dataset.index
const value = Number(e.target.value)
this.setState(prevState => prevState[index].quantity = value)
}
updatePrice(e) {
// Get the array index stored on the input.
// With that we can update the state.
const index = e.target.dataset.index
const value = Number(e.target.value)
this.setState(prevState => prevState[index].price = value)
}</code></pre>
<p>Then we need to update the <code>componentDidMount</code> hook and the <code>handleUpdate</code> method:</p>
<pre><code class="language-javascript">handleEvent(e) {
e.target.id === 'addRow' && this.addNewRow(e)
e.target.class === 'list__item__button--delete' && this.deleteRow(e)
e.target.class === 'quantity' && this.updateQuantity(e)
e.target.class === 'price' && this.updatePrice(e)
}
componentDidMount() {
this.element.addEventListener('click', this)
this.element.addEventListener('input', this)
}</code></pre>
<p>With these changes, we can now increase or decrease the price or quantity and see the row total and the spreadsheet sum update in real time. Here's what we have now:</p>
<p data-height="600" data-theme-id="6688" data-slug-hash="rYaJKE" data-default-tab="js,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-8" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/rYaJKE/">Composi Tuts - Thinking in Composi-8</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<p> </p>
<h2>Deleting a Row</h2>
<p>Each row has a delete button. This is so you can delete a row if you want. When this happens, the component state should update, showing the row is missing. Tapping the delete button should not delete the element from the DOM, like you would with jQuery. Instead it needs to remove the associated data from the component state. That in itself will cause the component to re-render without the deleted data.</p>
<p>When the user clicks the delete button, we need to know what index in the state array should be deleted. Earlier we had the same problem with know what index to update when modifying price and quantity. We used the <code>data-index</code> property to store the array index. When we did that, we also put that property on the row's delete button. So, we can now use that to now which index to delete. We will therefore add a new method to our button to handle deletion:</p>
<pre><code class="language-javascript">deleteRow(e) {
const index = e.target.dataset.index
this.setState(prevState => prevState.splice(index, 1))
}</code></pre>
<p>We also need to update the <code>handleEvent</code> method:</p>
<pre><code class="language-javascript">handleEvent(e) {
e.target.id === 'addRow' && this.addNewRow(e)
e.target.class === 'list__item__button--delete' && this.deleteRow(e)
e.target.class === 'quantity' && this.updateQuantity(e)
e.target.class === 'price' && this.updatePrice(e)
}</code></pre>
<p>With this our spreadsheet is complete. The spreadsheet will render its default data, we can add new items to it, we can update an item's price or quantity and the total and sum will update as well. And we can delete a row from the spreadsheet, causing the total and sum to update:</p>
<p data-height="600" data-theme-id="6688" data-slug-hash="aVzqXv" data-default-tab="js,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-9" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/aVzqXv/">Composi Tuts - Thinking in Composi-9</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<p> </p>
<h2>Breaking It Down</h2>
<p>Now we can begin breaking the component down into smaller pieces. We'll start with the easy parts, the table header and the Add Row form. Since they are simple, we'll make them function components that we can use in our component as custom tags:</p>
<pre><code class="language-javascript">function TableHeader() {
return (
<tr>
<th>Product</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<th></th>
</tr>
)
}
function AddNewRow() {
return (
<li class='list--spreadsheet__item'>
<div id='newRowForm'>
<p>
<label for="product">Product: </label>
<input name='product' id='product' type="text" tabindex='1' />
</p>
<p>
<label for="price">Price: </label>
<input name='price' id='price' type="text" tabindex='2' />
</p>
<p>
<label for="quantity">Quantity: </label>
<input name='quantity' id='quantity' type="text" tabindex='3' />
</p>
<p>
<button id='addRow'>Add Row</button>
</p>
</div>
</li>
)
}</code></pre>
<p>We can now use these in our spreadsheet component:</p>
<p data-height="600" data-theme-id="6688" data-slug-hash="GOgQay" data-default-tab="js,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-10" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/GOgQay/">Composi Tuts - Thinking in Composi-10</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<p>Hopefully you can see where we are going with this. Rather then step through the rest, we'll just show you the final solution, finely broken down into subcomponents. This implemented the principles of composition and props for data flowing down. The subcomponents are dumb in that they do not know about their parent. They do not even know if their parent is stateful or stateless. The get their data passed down through props. Here's the complete component with functional components getting props passed down:</p>
<p data-height="600" data-theme-id="6688" data-slug-hash="mqyxJX" data-default-tab="js,result" data-user="rbiggs" data-embed-version="2" data-pen-title="Composi Tuts - Thinking in Composi-11" class="codepen">See the Pen <a href="https://codepen.io/rbiggs/pen/mqyxJX/">Composi Tuts - Thinking in Composi-11</a> by Robert Biggs (<a href="https://codepen.io/rbiggs">@rbiggs</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<p> </p>
<h2>Tip</h2>
<p>After the first stage of creating a component, start breaking out subcomponents with the simplest parts first. When a subcomponent is still complex, break it into smaller parts gradually, one piece at at time, not all at once. That way if there is an error, it will be easier for you to find the cause.</p>
<h2>Inheritance vs Composition</h2>
<p>Composi offers a powerful class-based Component for building interfaces. You use it by extending it. This is classical inheritance, common in all object oriented programming languages. The principle is that you start with a base object and extend it to add new properties and methods. In face the browser's DOM works this way. At the same time, Composi encourages the use of composition to make complex component's more manageable. Extending the Component class one level is fine. Taking that extension and extending it again to add more featues is not a good strategy. Instead, look at how composition can help you make the complex hierarchies you need.</p>
<p> </p>
</div>
<aside>
<menu>
<ul class="tutorials__menu">
<li class="tutorials__menu__item">
<a href='./index.html'>Hello World</a>
</li>
<li class="tutorials__menu__item">
<a href='./introducing-jsx.html'>Introducing JSX</a>
</li>
<li class="tutorials__menu__item">
<a href='./rendering-elements.html'>Rendering Elements</a>
</li>
<li class="tutorials__menu__item">
<a href='./components-n-props.html'>Components and Props</a>
</li>
<li class="tutorials__menu__item">
<a href='./state-n-lifecycle.html'>State and Lifecycle</a>
</li>
<li class="tutorials__menu__item">
<a href='./conditional-rendering.html'>Conditional Rendering</a>
</li>
<li class="tutorials__menu__item">
<a href='./handling-events.html'>Handling Events</a>
</li>
<li class="tutorials__menu__item">
<a href='./lists-n-keys.html'>Lists and Keys</a>
</li>
<li class="tutorials__menu__item">
<a href='./forms.html'>Forms</a>
</li>
<li class="tutorials__menu__item">
<a href='./lifting-state-up.html'>Lifting State Up</a>
</li>
<li class="tutorials__menu__item selected">
<a href='./thinking-in-composi.html'>Thinking in Composi</a>
</li>
<li class="tutorials__menu__item">
<a href='./jsx-in-depth.html'>JSX In Depth</a>
</li>
<li class="tutorials__menu__item">
<a href='./advanced-state-management.html'>Advanced State Management</a>
</li>
<li class="tutorials__menu__item">
<a href='./composi-datastore.html'>Composi DataStore</a>
</li>
<li class="tutorials__menu__item">
<a href='./integrating-other-libs.html'>Integrating with Other Libraries</a>
</li>
<li class="tutorials__menu__item">
<a href='./composi-without-jsx.html'>Composi Without JSX</a>
</li>
<li class="tutorials__menu__item">
<a href='./immutable-data.html'>Immutable Data</a>
</li>
</ul>
</menu>
</aside>
</section>
</article>
<footer>
<section>
<svg id='composi-logo-footer' viewBox="0 0 300 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Composi Logo</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Composi-Logo-Solid" fill="rgba(255,255,255,0.5)">
<path d="M1.77635684e-15,0 L95,0 L95,38 L209,38 L209,0 L300,0 L300,94 L265,93.8571663 L265,209 L300,209 L300,300 L209,300 L209,265 L95,265 L95,300 L1.77635684e-15,300 L1.77635684e-15,209 L40,209 L40,94 L1.77635684e-15,93.8571663 L1.77635684e-15,0 Z M107,107 L107,192 L192,192 L192,107 L107,107 Z" id="Combined-Shape"></path>
</g>
</g>
</svg>
<h3>Composi is open source (MIT) and available on <a href='https://github.com/composor/composi' target='__blank'>Github</a> and <a href="https://www.npmjs.com/package/composi" target='__blank'>NPM</a>.</h3>
</section>
</footer>
<script src="../js/prism.min.js"></script>
<script src="../js/prism-jsx.js"></script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-115293685-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-115293685-1');
</script>
</body>
</html>