Date post: | 15-Apr-2017 |
Category: |
Software |
Upload: | frank-de-jonge |
View: | 9,982 times |
Download: | 0 times |
Frontin' LikeA Back-er
by @frankdejonge
The PHP League
Flysystem
2 million downloads, thank you!
There's no otheroption than using
JavaScript.- most of my friends
JavaScript is ameans to an end.
- almost all of my friends
If JavaScript isrequired, I'll hire
somebody.- my friends who have companies
If we hate something,why do we do it?
We all like the result:
Snappy UI / UX
I made a serverbrowser do this!
Loving JavaScriptHating JavaScript
Dealing with JavaScript
Take a step back.
React Reflect
$(window).load(function () { $('a.external-link').on('click', function clickHandler (e) { e.preventDefault();
if (confirm('Really?')) { $(this).off('click', clickHandler).click(); } });});
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.
Result drivenapproach.
Just enough code to make it work.
Looks goodat the front.
Not so prettyat the back.
Not good enough.Doesn't supply what I
need.
We need:1. Generated Elements; Templates?
2. XHR requests; Obviously, it's the future.3. Data Handling; Models? Collections?
Our saviours:
Backbone.js, Ember.js,Angular.js
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'; }});
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>
Ember.JS: Handlebars / Mustache.
23 page doc needed toexplain views.
You don't like JS andHTML; here's
something different.
It just doesn't work.
I'm OUT!Back to HTML.
Back-end flow:Receive HTTP Request.Process & Collect Data.Send Data => Template Engine.Send HTTP Response.
Current ApplicationState in HTML
Declarative<h1 class="hello">Hello World!</h1>
Composable<div class="hello"> <h1 class="hello__message">Hello World!</h1></div>
State & Behaviour<input type="checkbox" checked/>
Why can't it just be like that?
Just the UIJust like HTML
React (JS)
Definevar HelloWorld = React.createClass({ render: function () { return <h1>Hello, World!</h1>; }});
UseReact.render( <HelloWorld/>, document.getElementById('root'));
HTML in my JS?!What The Fudge!
#ProTip: Get over it.
JSX is just a DSL forHTML in JavaScript
Sugarvar HelloWorld = React.createClass({ render: function () { return <h1>Hello, World!<h1>; }});
Desugaredvar HelloWorld = React.createClass({ render: function () { return React.createElement( 'h1', {className: 'hello_world'}, 'Hello, World!' ); }});
Just like HTML:
It's declarative<ModalWindow/>
Just like HTML:
You can passproperties
<ModalWindow opened={true}/>
Just like HTML:
It's composable.<ModalWindow> <ModalHeader title="Hello World"/> <ModalBody> ... </ModalBody></ModalWindow>
It shows intent.<ProfileEditor> <Username /> <ProfilePicture /> <Biography /></ProfileEditor>
But where do I put my data?
React is all about the bass UI.
What is data in the UI?
Properties & State
Properties=
External Input
var Badge = React.createClass({ render: function () { return <div className="badge"> <h1>{this.props.name}</h1> <div>; }});
React.render( <Badge name="Kayla" />, document.getElementById('root'));
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);
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);
State=
Internal
var Toggle = React.createClass({ getInitialState: function () { return { completed: false }; }, render: function () { var className = this.state.completed ? 'toggle--completed' : 'toggle';
return <div className={className} />; }});
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} />; }});
Nice but what about
MY data?
Back-end data flow:1. Receive an HTTP request.2. Process + Get relevant data.3. Respond with a rendered view.
Back-end data flow:1. Action (intention)2. Domain (business stuff)3. Response (json/html/ ... xml?)
How does this map toJavaScript / React?
Front-end data flow:1. Action (intention)2. Domain (?)3. Response (React)
Front-end data flow:1. Action (intention)2. Store / Services (data layer)3. Response (React)
Stores hold theapplication state.
Services interactwith APIs.
Flux
Flux is only a patternThere are many implementations already.
Alt.jsActions & Stores
/actions//stores//components/
/alt.js/actions/TodoActions.js/stores/TodoStore.js/components/TodoApplication.js/components/TodoList.js
import Alt from 'alt';
let alt = new Alt();
export default alt;
// actions/TodoActions.js
import alt from '../alt';
class TodoActions { createTodo (task) { this.dispatch({ task }); }}
export default alt.createActions(TodoActions);
// 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');
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>; }});
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(); }});
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>; }});
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>; }});
import TodoList from './TodoList';
var TodoApplication = React.createClass({ render() { return <div className="todos"> <TodoList todos={this.state.todos} /> <input type="text"/> </div>; }});
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>; }});
So, what about myLaravel App?
// routes.php$app->post('/todos', function (Request $request) { $todo = $request->json()->all(); // Store the TODO return new JsonResponse($todo->all());});
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');
What do we know sofar?
Writing front-end code, like back-end code.
It's all about data-flow.
Intent is everything.
Complexity should be facilitated.
Choose a tool thatsupports it.
React can runon the server.
Declarative UIacross the board.
Thank you foryour time!