Thinking in components
Why, what and how
Alex Peattie
CTO & co-founder Peg
alex@peg.co
Let's talk about
- Why use components in the first place?
- What are components (and what are they not)?
- How do we use them in practice?
Why?
- All major front-end frameworks embracing components (Angular, React, Backbone, Vue etc. etc.)
- Web components to be added to all browsers by ~2017
- They will make your life as a dev easier 😄!
Addy Osmani's rules for components: FIRST
- Focused
- Independent/Isolated
- Reusable
- Small
- Testable
Also a great manifesto for why to use components!
- Changed code and had it break a different part of the application
- Tried to add a "minor" improvement only having to unravel a bunch of code you didn't understand
- Run into a brick wall trying to test your front-end
- Wanted to open-source a cool part of your app
If you've ever
Components might be what you need!
Case study: Peg
10K lines of JS, large "God" controllers
What?
<ng-include src='navbar.html'></ng-include>
<ng-include src='search-area.html'></ng-include>
<section class='results'>
<ng-include src='creator.html'
ng-repeat='creator in creators'>
</ng-include>
</section>
Components != partials
- Act like normal HTML elements:
- All the code (HTML, CSS & JS) is packaged up together
- They have inputs & outputs, just like methods
<payment-button>Pay Now!</payment-button>
How?
function starsignForBirthday(day, month) {
// some clever stuff
return starsign;
}
starsignForBirthday(24, 8) // "Virgo"
starsignForBirthday(1, 1) // "Capricorn"
starsignForBirthday(10000) // Error
<input id='cc' type='number' pattern='[0-9]{16}'>
<button class='payment-button disabled' type='submit'>
.payment-button {
background: blue;
&.success {
background: green;
}
&.failed {
background: red;
}
&.disabled {
cursor: disabled;
background: grey;
}
}
$('#cc').on('keydown', function() {
var isValid = $(this).valid()
$('.payment-button').toggleClass('disabled', !isValid)
})
$('.payment-button').on('click', function() {
var ccNum = $('#cc').val()
$('.payment-button').text('Paying')
$.post('https://api.stripe.com/pay', { num: ccNum }, function() {
$('.payment-button').text('Paid').addClass('success')
}, function() {
$('.payment-button').text('Failed').addClass('failed')
})
})
Credit card valid
No
Yes
Payment
status
Waiting
Processing
Success
Failure
function starsignForBirthday(day, month) {
return starsign;
}
<payment-button credit-card='...' payment-status='...'>
</payment-button>
paymentButton = {
bindings: {
cardNumber: '<',
paymentStatus: '<'
}
}
this.paymentStatus = this.paymentStatus || 'waiting'
this.pay = function() {
this.paymentStatus = 'processing'
$http.post('http://api.stripe.com/pay', { num: this.cardNumber },
function() {
this.paymentStatus = 'success'
}, function() {
this.paymentStatus = 'failed'
})
}
angular.component('<payment-button>', paymentButton) // <- pseudocode
<button ng-class='{ disabled: !component.creditCard.$valid }'
ng-switch='component.paymentStatus' ng-click='component.pay()'>
<span ng-switch-when='waiting'>Pay</span>
<span ng-switch-when='processing'>Paying</span>
<span ng-switch-when='success'>Paid</span>
<span ng-switch-when='failure'>Failure</span>
</button>
- Focused ✅
- Independent/Isolated ✅
- Reusable ✅
- Small ✅
- Testable ✅
<payment-button></payment-button>
<payment-button payment-status='success'></payment-button>
expect($('payment-button').text()).toEqual('Paid')
Credit card valid
No
Yes
Payment
status
Waiting
Processing
Success
Failure
<button ng-class='{ disabled: !component.creditCard.$valid }'
ng-switch='component.paymentStatus'>
$('#cc').on('keydown', function() {
var isValid = $(this).valid()
$('.payment-button').toggleClass('disabled', !isValid)
})
<button
ng-class='{
disabled: !component.creditCard.$valid && component.paymentStatus === "waiting"
}'
ng-switch='component.paymentStatus'>
$('#cc').on('keydown', function() {
var isValid = $(this).valid()
// Horrible hack ⬇
var paymentWaiting = $('.payment-button').text() === "Pay"
$('.payment-button').toggleClass('disabled', !isValid && paymentWaiting)
})
$('.payment-button').on('click', function() {
$(this).removeClass('disabled')
})
<favourite-button creator='zoella'>
<button-toggler toggled='creator.favourited'>
<button ng-click='add()'>Favourite</button>
<button ng-click='remove()'>Favourited</button>
</button>
<notification position='bottom-center' notify-status='request.status'
notify-status-when='200'>
{{ creator.name }} has been favourited
</notification>
<notification position='bottom-center' notify-status='request.status'
notify-status-when='4xx'>
Oops something went wrong!
</notification>
</favourite-button>
<favourite-button creator='zoella'>
<button-toggler toggled='creator.favourited'>
</button>
<notification position='bottom-center'
notify-status='request.status'
notify-status-when='200'>
Favourite button
Responsible for favouriting/unfavouriting creators
Inputs: the creator in question
Button toggler
Responsible for toggling the visibilty of its child buttons
Inputs: is it currently toggled?
Notification
Responsible for notifying the user about successful/failed HTTP requests
Inputs: the HTTP request status it's watching, which code triggers the notification to appear
Conclusion
- Components are the future
- They help you avoid spaghetti code
- Good components should be FIRST (focused, isolated, reusable, small, testable)
- Think about components like methods (thinking about inputs and outputs)
- Keep components small by making them work together (composing them)
Thank you!
any questions?
PS - slides are online at:
https://slides.com/alexpeattie/components
Thinking in components
By alexpeattie
Thinking in components
"Reusable component" has become a bit of buzzword - it's the philosophy driving popular frameworks like React, Angular 2 and Vue. And they're set to become part of a web devs' bread-and-butter with the imminent arrival of Web Components to HTML5 (ETA 2017). But what are components, and why are they useful? How do we shift our minds to start "thinking in components"? I'll look at these questions in the talk, drawing on my experience moving our large-scale app (peg.co) to a component-based approach.
- 2,110