2013 2014 2015 It was definitely a move forward from the previous practice of vending everything in /public. But it came with a whole new set of problems, and unfortunately the future didn’t work out this way.
... }); // account.js $(function() { ... }); // templates.js $(function() { ... }); // controllers.js $(function() { ... }); But all it does is produce a bunch of concatenated javascript named application.js, which typically includes a new DOM ready callback for each function, just to be sure it is safe to run and manipulate the DOM.
code We get paid to build products which customers love you don’t get paid for the aesthetics of your code. You get paid to delivery great products, and part of any great product is a great user experience. And the expectation is quickly becoming that any great user experience will involve javascript. So let’s treat it as a first class citizen in our applications.
for the aesthetics of your code. You get paid to delivery great products, and part of any great product is a great user experience. And the expectation is quickly becoming that any great user experience will involve javascript. So let’s treat it as a first class citizen in our applications.
get paid for the aesthetics of your code. You get paid to delivery great products, and part of any great product is a great user experience. And the expectation is quickly becoming that any great user experience will involve javascript. So let’s treat it as a first class citizen in our applications.
paid for the aesthetics of your code. You get paid to delivery great products, and part of any great product is a great user experience. And the expectation is quickly becoming that any great user experience will involve javascript. So let’s treat it as a first class citizen in our applications.
the aesthetics of your code. You get paid to delivery great products, and part of any great product is a great user experience. And the expectation is quickly becoming that any great user experience will involve javascript. So let’s treat it as a first class citizen in our applications.
var ComponentA = MyDependency.extend({ ... }); export default ComponentA; Let’s look at the future. This is an ES6 module. ES6 is the next generation of JS which is still largely in a proposal state, but some parts can be transpiled to ES5 today. Like this module.
inside a headless browser, or on the server, because it’s all isolated. This makes testing more consistent with other languages. You don’t need to spin up the whole stack to run your JS tests
├── application.js └── vendor.js So we might have a structure like this, notice we have some underscored prefixes on application and vendor. These are our webpack entry point files. Everything in here will be compiled to a bundle file inside vendor/assets/javascripts
{React Component} */ window.App = require('./app').default; Inside _application.js we might have some requires like this. This is all valid javascript, using the commonJS require conventions, which will be picked up by Webpack
want to include in vendor.bundle and * webpack will package it here instead * of the application.bundle. */ require('react'); require('react/addons'); One of the really useful features of webpack is chunking. You can create a vendor chunk which just loads the libraries, so you can have a large vendor bundle which changes rarely and a small app bundle which changes often, which is ideal for CDN caching.
//= require jquery_ujs //= require vendor.bundle Inside the actual vendor.js we just tell the Asset Pipeline to load our compiled static bundle, and the same in application.js
__dirname + '/app/assets/javascripts', entry: { application: './_application.js', vendor: './_vendor.js', }, output: { filename: '[name].bundle.js', path: __dirname + '/vendor/assets/javascripts', }, }; The Webpack config to make all this work is actually quite simple, we have an entry point which loads our modular JS requires, and an output, which dumps the static assets.
5780ms Asset Size Chunks Chunk Names vendor.bundle.js 648825 0 [emitted] vendor application.bundle.js 301145 1 [emitted] application + 201 hidden modules We can then run the webpack command line tool and output our JS bundles ready for rails to load. There’s also a handy — watch flag to have webpack recompile when things change.
here, it’s a whole topic in itself. But you can either test webpack modules in the browser, or on the server with Node.js, and here’s the Webpack testing guide.
its own internal state and properties, nothing more. When the state changes, React renders a virtual DOM representation of the component based on that state.
the DOM diffing, or reconciliation. Once we have a virtual DOM output, React diffs this against the real DOM, then merges the changes with the real DOM, very efficiently. You can read about the crazy heuristics which make this work
component is always represented in the DOM, no separation of templates and view logic, because they should be tightly coupled, because that’s how they usually get used.
{ return <div>Hello {this.props.name}</div>; } }); export default MyComponent; Here’s an example component. Notice the weird inline HTML stuff, isn’t that crazy?
{ return React.createElement("div", null, "Hello ", this.props.name); } }); export default MyComponent; That’s JSX, which you can compile on the server or the client, or not use at all, because it only gets converted to JS.
You can treat the state of your top level component as the definitive source of truth and just re-render the whole UI every time something changes. This enforces an easy to reason about single direction of data flow.
2” /> <ListItemComponent name=“Item 3” /> So an example UI might be composed like this. Your life with React will be significantly easier when each component is kept as simple as possible.
{name: "Item 1"}, {name: "Item 2"}, ]}; }, render: function() { var listItems = this.state.items.map(function(item) { return <ListItemComponent name={ item.name } />; }); return ( <ul>{ listItems }</ul> ); } }); One thing I really like about React is that you can use standard javascript operators to handle composing your UI. Example here we use map on an array of items to return another array of item components, which we then render in a list
}); this.setState({ items: items }); }, render: function() { var listItems = this.state.items.map(function(item) { return <ListItemComponent name={ item.name } />; }); return ( <div> <ul>{ listItems }</ul> <a onClick={ this.clickHandler }>Add Item</a> </div> ); } }); This makes adding new items to our list as simple as updating the state, in this case just pushing a new item on to the array.