frontin like-a-backer

91
Frontin' Like A Back-er by @frankdejonge

Upload: frank-de-jonge

Post on 15-Apr-2017

9.984 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Frontin like-a-backer

Frontin' LikeA Back-er

by @frankdejonge

Page 2: Frontin like-a-backer

The PHP League

Flysystem

Page 3: Frontin like-a-backer

2 million downloads, thank you!

Page 4: Frontin like-a-backer
Page 5: Frontin like-a-backer
Page 6: Frontin like-a-backer
Page 7: Frontin like-a-backer

There's no otheroption than using

JavaScript.- most of my friends

Page 8: Frontin like-a-backer

JavaScript is ameans to an end.

- almost all of my friends

Page 9: Frontin like-a-backer

If JavaScript isrequired, I'll hire

somebody.- my friends who have companies

Page 10: Frontin like-a-backer

If we hate something,why do we do it?

Page 11: Frontin like-a-backer

We all like the result:

Snappy UI / UX

Page 12: Frontin like-a-backer

I made a serverbrowser do this!

Page 13: Frontin like-a-backer
Page 14: Frontin like-a-backer

Loving JavaScriptHating JavaScript

Dealing with JavaScript

Page 15: Frontin like-a-backer

Take a step back.

React Reflect

Page 16: Frontin like-a-backer

$(window).load(function () { $('a.external-link').on('click', function clickHandler (e) { e.preventDefault();

if (confirm('Really?')) { $(this).off('click', clickHandler).click(); } });});

Page 17: Frontin like-a-backer

This is not separation of concerns.<a class="hide-me">Click and I'll disappear</a>

<script type="application/javascript"> $('a.hide_me').on('click', function (e) { e.preventDefault(); $(this).hide(); });</script>

It's error-prone.

Page 18: Frontin like-a-backer

Result drivenapproach.

Just enough code to make it work.

Page 19: Frontin like-a-backer

Looks goodat the front.

Page 20: Frontin like-a-backer

Not so prettyat the back.

Page 21: Frontin like-a-backer

Not good enough.Doesn't supply what I

need.

Page 22: Frontin like-a-backer

We need:1. Generated Elements; Templates?

2. XHR requests; Obviously, it's the future.3. Data Handling; Models? Collections?

Page 23: Frontin like-a-backer

Our saviours:

Backbone.js, Ember.js,Angular.js

Page 24: Frontin like-a-backer

Backbone.JS: You figure it out.var DocumentRow = Backbone.View.extend({ tagName: "li", className: "document-row", events: { "click .icon": "open", }, initialize: function() { this.listenTo(this.model, "change", this.render); }, render: function() { var idea = 'I have none'; }});

Page 25: Frontin like-a-backer

Angular.JS: ng-whatever.<html ng-app="phonecatApp"><head> <script src="bower_components/angular/angular.js"></script> <script src="js/controllers.js"></script></head><body ng-controller="PhoneListCtrl"> <ul> <li ng-repeat="phone in phones"> <span>{{phone.name}}</span> <p>{{phone.snippet}}</p> </li> </ul></body></html>

Page 26: Frontin like-a-backer

Ember.JS: Handlebars / Mustache.

23 page doc needed toexplain views.

Page 27: Frontin like-a-backer

You don't like JS andHTML; here's

something different.

Page 28: Frontin like-a-backer

It just doesn't work.

Page 29: Frontin like-a-backer

I'm OUT!Back to HTML.

Page 30: Frontin like-a-backer

Back-end flow:Receive HTTP Request.Process & Collect Data.Send Data => Template Engine.Send HTTP Response.

Page 31: Frontin like-a-backer

Current ApplicationState in HTML

Page 32: Frontin like-a-backer

Declarative<h1 class="hello">Hello World!</h1>

 

Composable<div class="hello"> <h1 class="hello__message">Hello World!</h1></div>

Page 33: Frontin like-a-backer

State & Behaviour<input type="checkbox" checked/>

Page 34: Frontin like-a-backer

Why can't it just be like that?

Just the UIJust like HTML

Page 35: Frontin like-a-backer

React (JS)

Page 36: Frontin like-a-backer

Definevar HelloWorld = React.createClass({ render: function () { return <h1>Hello, World!</h1>; }});

 

UseReact.render( <HelloWorld/>, document.getElementById('root'));

Page 37: Frontin like-a-backer

HTML in my JS?!What The Fudge!

Page 38: Frontin like-a-backer

#ProTip: Get over it.

Page 39: Frontin like-a-backer

JSX is just a DSL forHTML in JavaScript

Page 40: Frontin like-a-backer

Sugarvar HelloWorld = React.createClass({ render: function () { return <h1>Hello, World!<h1>; }});

Page 41: Frontin like-a-backer

Desugaredvar HelloWorld = React.createClass({ render: function () { return React.createElement( 'h1', {className: 'hello_world'}, 'Hello, World!' ); }});

Page 42: Frontin like-a-backer

Just like HTML:

It's declarative<ModalWindow/>

Page 43: Frontin like-a-backer

Just like HTML:

You can passproperties

<ModalWindow opened={true}/>

Page 44: Frontin like-a-backer

Just like HTML:

It's composable.<ModalWindow> <ModalHeader title="Hello World"/> <ModalBody> ... </ModalBody></ModalWindow>

Page 45: Frontin like-a-backer

It shows intent.<ProfileEditor> <Username /> <ProfilePicture /> <Biography /></ProfileEditor>

Page 46: Frontin like-a-backer

But where do I put my data?

React is all about the bass UI.

Page 47: Frontin like-a-backer

What is data in the UI?

Properties & State

Page 48: Frontin like-a-backer

Properties=

External Input

Page 49: Frontin like-a-backer

var Badge = React.createClass({ render: function () { return <div className="badge"> <h1>{this.props.name}</h1> <div>; }});

React.render( <Badge name="Kayla" />, document.getElementById('root'));

Page 50: Frontin like-a-backer

var Badge = React.createClass({ render: function () { var description = this.props.is_awesome ? 'is awesome!' : 'is not awesome';

return <div className="badge"> <h1>{this.props.text}</h1> <p> {description} </p> <div>; }});

React.render(<Badge name="Kayla" is_awesome={true} />, rootNode);

Page 51: Frontin like-a-backer

var BadgeList = React.createClass({ render: function () { var badges = this.props.people.map(function (person) { return <Badge key={person.id} {...person} />; });

return <div className="badge_list">{badges}<div>; }});

React.render(<BadgeList people={peopleCollection} />, rootNode);

Page 52: Frontin like-a-backer

State=

Internal

Page 53: Frontin like-a-backer

var Toggle = React.createClass({ getInitialState: function () { return { completed: false }; }, render: function () { var className = this.state.completed ? 'toggle--completed' : 'toggle';

return <div className={className} />; }});

Page 54: Frontin like-a-backer

var Toggle = React.createClass({ getInitialState: function () { return { completed: false }; }, onClick: function () { this.setState({completed: ! this.state.completed}); }, render: function () { var className = this.state.completed ? 'toggle--completed' : 'toggle';

return <div onClick={this.onClick} className={className} />; }});

Page 55: Frontin like-a-backer

Nice but what about

MY data?

Page 56: Frontin like-a-backer

Back-end data flow:1. Receive an HTTP request.2. Process + Get relevant data.3. Respond with a rendered view.

Page 57: Frontin like-a-backer

Back-end data flow:1. Action (intention)2. Domain (business stuff)3. Response (json/html/ ... xml?)

Page 58: Frontin like-a-backer

How does this map toJavaScript / React?

Page 59: Frontin like-a-backer

Front-end data flow:1. Action (intention)2. Domain (?)3. Response (React)

Page 60: Frontin like-a-backer

Front-end data flow:1. Action (intention)2. Store / Services (data layer)3. Response (React)

Page 61: Frontin like-a-backer

Stores hold theapplication state.

Page 62: Frontin like-a-backer

Services interactwith APIs.

Page 63: Frontin like-a-backer

 

Page 64: Frontin like-a-backer

Flux

Page 65: Frontin like-a-backer

Flux is only a patternThere are many implementations already.

Page 66: Frontin like-a-backer

Alt.jsActions & Stores

Page 67: Frontin like-a-backer

/actions//stores//components/

Page 68: Frontin like-a-backer
Page 69: Frontin like-a-backer

/alt.js/actions/TodoActions.js/stores/TodoStore.js/components/TodoApplication.js/components/TodoList.js

Page 70: Frontin like-a-backer
Page 71: Frontin like-a-backer
Page 72: Frontin like-a-backer

import Alt from 'alt';

let alt = new Alt();

export default alt;

Page 73: Frontin like-a-backer

// actions/TodoActions.js

import alt from '../alt';

class TodoActions { createTodo (task) { this.dispatch({ task }); }}

export default alt.createActions(TodoActions);

Page 74: Frontin like-a-backer

// stores/TodoStore.jsimport alt from '../alt';import TodoActions from '../actions/TodoActions';

class TodoStore { constructor() { this.todos = []; this.bindListeners({ handleCreatedTodo: TodoActions.CREATE_TODO }); } handleCreatedTodo (todo) { this.todos.push(todo); }}export default alt.createStore(TodoStore, 'TodoStore');

Page 75: Frontin like-a-backer

import React from 'react';

var TodoApplication = React.createClass({ render() { var todoList = this.state.todos.map(function (todo, index) { return <li key={index}>{todo.task}</li>; });

return <div className="todos"> <ul className="todo__list"> {todoList} </ul> <input type="text"/> </div>; }});

Page 76: Frontin like-a-backer

import TodoStore from '../stores/TodoStore';

var TodoApplication = React.createClass({ componentWillMount () { TodoStore.listen(this.handleChange); } componentWillUnmount () { TodoStore.unlisten(this.handleChange); } handleChange (state) { this.setState(state); } getInitialState() { return TodoStore.getState(); }});

Page 77: Frontin like-a-backer

var TodoApplication = React.createClass({ render() { var todoList = this.state.todos.map(function (todo, index) { return <li key={index}>{todo.task}</li>; });

return <div className="todos"> <ul className="todo__list"> {todoList} </ul> <input type="text"/> </div>; }});

Page 78: Frontin like-a-backer

var TodoList = React.createClass({ render() { var todoList = this.props.todos.map(function (todo, index) { return <li key={index}>{todo.task}</li>; });

return <ul className="todo__list"> {todoList} </ul>; }});

Page 79: Frontin like-a-backer

import TodoList from './TodoList';

var TodoApplication = React.createClass({ render() { return <div className="todos"> <TodoList todos={this.state.todos} /> <input type="text"/> </div>; }});

Page 80: Frontin like-a-backer

import TodoList from './TodoList';import TodoActions from '../actions/TodoActions';

var TodoApplication = React.createClass({ handleCreateTodo (event) { if (event.keyCode !== 13) return; var task = event.target.value; TodoAction.createTodo(task); } render() { return <div className="todos"> <TodoList todos={this.state.todos} /> <input type="text" onKeyDown={this.handleCreateTodo}/> </div>; }});

Page 81: Frontin like-a-backer

So, what about myLaravel App?

Page 82: Frontin like-a-backer

// routes.php$app->post('/todos', function (Request $request) { $todo = $request->json()->all(); // Store the TODO return new JsonResponse($todo->all());});

Page 83: Frontin like-a-backer

import alt from '../alt';import TodoActions from '../actions/TodoActions';

class TodoStore { handleCreatedTodo (todo) { fetch('/todos', { method: 'post', body: JSON.stringify(todo) }).then((response) => { this.todos.push(response.json()); this.emitChange(); }); }}export default alt.createStore(TodoStore, 'TodoStore');

Page 84: Frontin like-a-backer

What do we know sofar?

Page 85: Frontin like-a-backer

Writing front-end code, like back-end code.

It's all about data-flow.

Page 86: Frontin like-a-backer

Intent is everything.

Page 87: Frontin like-a-backer

Complexity should be facilitated.

Choose a tool thatsupports it.

Page 88: Frontin like-a-backer
Page 89: Frontin like-a-backer

React can runon the server.

Page 90: Frontin like-a-backer

Declarative UIacross the board.

Page 91: Frontin like-a-backer

Thank you foryour time!