This is part of the Ext JS to React blog series. You can review the code from this article on the Ext JS to React Git repo.
Previously, we looked at simple template examples with Ext JS and React. In this blog, we’d like to look at some more advanced examples. This includes the use of member functions and inline value formatters from Ext JS and how the same techniques are accomplished with React. For consistency, we’ll use the same data set defined in the Simple Templating post.
Ext JS template example
In the last post, we saw how to get started with templates in both the Ext JS and React worlds. In the Ext JS example, we needed to encode the greater-than symbol to describe a comparator and that is ugly.
'<tpl if="people.length > 0">' +
For this first example, let’s say we want to format the number showing how many people belong to the company. The formatter will include a comma as necessary; let’s return the email value as a clickable link. The updated component would be:
Ext.define('MyComponent', { extend: 'Ext.Component', xtype: 'mycomponent', tpl: [ '<h1>{name}</h1>' + '<div>' + '<h2>Address:</h2>' + '<div>{address.street}</div>' + '<div>{address.city}, {address.state} {address.zip}</div>' + '</div>' + '<tpl if="this.hasPeople(people)">' + '<div>' + '<h2>People ({people.length:number("0,0")}):</h2>' + '<ul>' + '<tpl for="people">' + '<li>' + '<div>{name}</div>' + '<div>{[this.linkifyEmail(values.email)]}</div>' + '<div>Skills:</div>' + '<ul>' + '<tpl for="skills">' + '<li>{.}</li>' + '</tpl>' + '</ul>' + '</li>' + '</tpl>' + '</ul>' + '</div>' + '<tpl else>' + '<div>No people found</div>' + '</tpl>', { hasPeople : function (arr) { return arr.length > 0; }, linkifyEmail : function (email) { return '<a href="mailto:' + email + '">' + email + '</a>'; } } ] });
Ext JS example rundown
For our Ext JS example, the first change we made was to have the tpl
config on the component be an array. That way, the template as a string is the first item in the array and an object composed of methods will be the second array item. To get rid of the greater-than encoding, we now call this.hasPeople
. This is mapped to the hasPeople
method in that second array item object. The hasPeople
function is called a “member function”.
The next change was to format the number of people the company has. If there are over a thousand people, it’s displayed with a comma. This is done by adding a colon and the type of formatter to be used. Formatter functions are defined on Ext.util.Format
. In this case, we use the number formatter. The last change is to call a member function within curly braces in order to call the linkifyEmail
member function returning the link. Take note of the square brackets within the curly braces as this is what tells the template to expect raw JavaScript. You can do a lot within the square brackets including ternary conditionals.
React template example
The equivalent changes in React would be:
import React, { Component } from 'react'; class Members extends Component { render () { const { data } = this.props; return ( <div> <h1>{data.name}</h1> <div> <h2>Address:</h2> <div>{data.address.street}</div> <div>{data.address.city}, {data.address.state} {data.address.zip}</div> </div> <div> { this.hasPeople(data.people) ? <div> <h2>People ({data.people.length.toLocaleString('en')}):</h2> <ul> { data.people.map(person => ( <li> <div>{person.name}</div> <div> <a href={`mailto:${person.email}`}>{person.email}</a> </div> <div>Skills</div> <ul> { person.skills.map(skill => <li>{skill}</li>) } </ul> </li> )) } </ul> </div> : <div>No people found</div> } </div> </div> ); } hasPeople (arr) { return arr.length > 0; } } export default Members;
React application example
To use the Members class (with the same data we set up for the Ext JS example above):
import React, { Component } from 'react'; import Members from './Members'; import './App.css'; const data = { name : 'Smith Corp', address : { street : '1 Smith Blvd', city : 'Smithville', state : 'Smith', zip : 12345 }, people : [{ name : 'Bob Smith', email : 'bob@smith.com', skills : ['cooking', 'building'] }, { name : 'Jane Smith', email : 'jane@smith.com', skills : ['managing', 'presenting'] }] }; class App extends Component { render() { return ( <Members data={data}/> ); } } export default App;
React example rundown
In JSX, anything between curly braces can be JavaScript. In the case of the inline people-length check, we call the hasPeople
method on the class. The hasPeople
method is akin to using “template member functions” in Ext JS’s XTemplates. Now the logic can live on the class body or within a utility function shared across the application. This makes managing template logic a bit more elegant than the syntax used with “template member functions”. Although this isn’t required (it’s preferred to keep inline for such a simple check), it still serves as a good example of calling class methods within JSX.
In the example, we chose to render the person data using an array.map()
call within the JSX. This showed how arbitrary code may be executed within JSX in addition to calling methods on the class like we did with hasPeople
. Often times you’ll want to move this sort of bulk logic into a dedicated method. Then call it from within curly braces for improved readability of the JSX itself.
To format the people count, the toLocaleString
method on a number can be used. A class member and a formatting package could be installed and used, especially when working with dates. The bigger change was how the email was turned into a link. React says a string should purely be a string and any HTML entities within the string should be encoded to avoid dangerous injections. This is fine since in JSX it’s preferable to use an anchor node as you would with a div
. If you have to render a string as actual DOM nodes and you trust that string, you can use React’s dangerouslySetInnerHTML API. It’s use is not recommended unless it’s unavoidable and you absolutely trust the HTML sent by the server.
Template conditionals
In our example, we processed a bit of logic using a conditional with a ternary expression using a call to this.hasPeople. Another common handling of conditionals is to evaluate a boolean and process additional JSX if the check is true. For example, if we wanted to render a link to a person’s email only if the person object contained an email address, we could do something like:
{person.mail && <a href={`mailto:${person.email}`}>{person.email}</a>}
If mail is truthy then we render the anchor element. For those that are more comfortable with the conditional syntax used with Ext JS templates, fret not. You can look at extending what Babel processes as a conditional using the jsx-control-statement Babel plugin. The plugin allows you to write out conditional checks with syntax like:
<If condition={person.mail}> <a href={`mailto:${person.email}`}>{person.email}</a> </If>
Conclusion
Once again, JSX with React simplifies templating by presenting a natural syntax that is immediately familiar. Ext JS does have some handy API functionality (like formatting a number), though the API you’re required to use is less intuitive than the syntax supported within JSX. Ultimately, the good news is that if you were familiar with the templating mechanics in Ext JS you’ll be right at home with the declarative and compositional nature of JSX. If you hadn’t really had to learn templating in your past Ext JS work, you’ll be right at home with the declarative and compositional nature of JSX!
Mitchell Simoens
Related Posts
-
Ext JS to React: Migration to Open Source
Worried about Migrating from Ext JS? Modus has the Answers Idera’s acquisition of Sencha has…
-
Ext JS to React: FAQ
This is part of the Ext JS to React blog series. React is Facebook's breakout…