SenchaCon 2016: Ext JS + React: A Match Made in UX Heaven - Mark Brocato

Post on 15-Apr-2017

170 views 1 download

Transcript of SenchaCon 2016: Ext JS + React: A Match Made in UX Heaven - Mark Brocato

Ext JS + ReactA Match Made in UX Heaven

Mark BrocatoSr. Engineering Manager, Sencha

My Journey to React

My Journey to React

Scenario Builder

My Journey to React

My Journey to React

My Journey to React

My Journey to React

React Primer

• A JavaScript library for building user interfaces

• React is the just the V in MVC

• Solve one problem: Build large applications with data that changes over time.

React Components

Componentdata

HTML

Views as Pure Functions

dataHTMLFunction

Views as Componentsimport React, { Component } from 'react'; class NewsFeed extends Component { render() { const { news } = this.props; return ( <ul> { news.map(story => ( <li> <div className="title">{story.title}</div> <div>by {story.author}</div> </li> )) } </ul> ) } }

Views as Pure Functions

function NewsFeed({ news }) { return ( <ul> { news.map(story => ( <li> <div className="title">{story.title}</div> <div>by {story.author}</div> </li> )) } </ul> ) }

JSX

<div className="title">{story.title}</div>

JSX

<div className="title">{story.title}</div>

React.createElement('div', { className: 'title'}, store.title)

Views as Components

function NewsFeed({ news }) { return ( React.createElement('ul', {}, news.map(story => { return React.createElement('li', {}, [ React.createElement('div', { className: 'title' }, store.title), React.createElement('div', { }, `by ${store.author}`) ]) })); ) }

React’s One-Way Data Flow (Flux)

Store

Component Component Component

Component Component Component Component

dataAPI

Virtual DOM to the Rescue

React and Ext JS Similarities

• Ext.Component

• configs

• items: []

• React.Component

• props

• children

What’s Missing?

✔ Routing: react-router✔ Architecture: redux

Components

@extjs/reactor

React Hello Worldimport React from 'react'; import ReactDOM from 'react-dom'; ReactDOM.render( ( <div> Hello World! </div> ), document.getElementById('root') );

React Hello World w/ Ext JSimport React from 'react'; import ReactDOM from 'react-dom'; import install from ’@extjs/reactor'; install(); Ext.onReady(() => { ReactDOM.render( ( <x-panel title="Ext JS in React"> Hello World! </x-panel> ), document.getElementById('root') ); });

@extjs/reactor

• Use any xtype as a JSX tag.

• Mix and match HTML and Ext JS

import React from 'react'; import ReactDOM from 'react-dom'; import install from ’@extjs/reactorjs'; install(); Ext.onReady(() => { ReactDOM.render( ( <x-panel title="Ext JS in React"> Hello World! </x-panel> ), document.getElementById('root') ); });

Ext.create({ xtype: 'panel', title: 'Ext JS in React', html: 'Hello World!'});

Responding to Events

• All props starting with “on” are automatically converted to Ext JS event listeners

• You can also specify event handlers using a listeners prop, just like in traditional Ext JS

import React, { Component } from 'react'; class MyComponent extends Component { onSliderChange(slider, value) { console.log('value', value); } render() { return ( <x-slider

onChange={this.onSliderChange.bind(this)}/>

) } }

Responding to Events

• All props starting with “on” are automatically converted to Ext JS event listeners

• You can also specify event handlers using a listeners prop, just like in traditional Ext JS

import React, { Component } from 'react'; class MyComponent extends Component { onSliderChange(slider, value) { console.log('value', value); } render() { return ( <x-slider

onChange={this.onSliderChange.bind(this)}/>

) } }

Ext.create({ xtype: 'slider', listeners: {

change: this.onSliderChange }});

Component Refs

• As with DOM elements, you can access Ext components by adding a “ref” prop.

• Here this.refs.slider is an instance of Ext.slider.Slider

import React, { Component } from 'react'; class MyComponent extends Component { onSliderChange(slider, value) { console.log('value', this.refs.slider.getValue()); } render() { return ( <x-slider

ref="slider" onChange={this.onSliderChange.bind(this)}

/> ) } }

More Complex Configs

• It’s all just JavaScript.

• React props => Ext JS configs

class MyComponent extends Component { render() { return ( <x-grid plugins={[ { type: 'columnresizing' } ]} columns={[ { text: 'Name', dataIndex: 'name' }, { text: 'Email', dataIndex: 'email' } ]} store={{ data: [ ...

] }} /> ) } }

Layouts

• Work like you’d expect

class MyComponent extends Component { render() { return ( <x-container layout="hbox"> <x-button text="Left"/> <x-button text="Right"/> </x-container> ) } }

Layouts

• Work like you’d expect

class MyComponent extends Component { render() { return ( <x-container layout="hbox"> <x-button text="Left"/> <x-button text="Right"/> </x-container> ) } }

Ext.create({ xtype: 'container', layout: 'hbox', items: [ { xtype: 'button', text: 'Left' }, { xtype: 'button', text: 'Right' } ]});

Updates

• When a prop changes, @extjs/reactor automatically calls the corresponding setter method to update your component’s configs.

class MyComponent extends Component {

constructor(props) { super(props); this.state = { dirty: true }; } render() { const text = this.state.dirty ? "Save Changes" : "Changes Saved"; return ( <x-button text={text} handler={this.onClick.bind(this)} /> ) } onClick() { this.setState({ dirty: false }); }

}

Updates

• When a prop changes, @extjs/reactor automatically calls the corresponding setter method to update your component’s configs.

class MyComponent extends Component {

constructor(props) { super(props); this.state = { dirty: true }; } render() { const text = this.state.dirty ? "Save Changes" : "Changes Saved"; return ( <x-button text={text} handler={this.onClick.bind(this)} /> ) } onClick() { this.setState({ dirty: false }); }

}

button.setText(text);

Summing Up

props configs

on/A-Z/ listeners

child elements items: []

updates setter calls

@extjs/reactor-webpack-plugin

Setting up your React app for Ext JS

ext-all.js reactor-webpack-plugin

Automatic Usage Detectionimport React, { Component } from 'react'; Ext.require('Ext.window.Toast'); export default class MyDialog extends Component { constructor(props) { super(props); this.store = Ext.create('Ext.data.Store', { ... }); } render ( <x-window> <x-grid ... /> </x-window> ) }

ext.js

ext.css

Configure Theme, Toolkit, and Packages

const ExtJSReactorWebpackPlugin = require('@extjs/reactor-webpack-plugin'); module.exports = { ... plugins: [ new ExtJSReactorWebpackPlugin({ sdk: 'ext', // relative or full path to Ext JS SDK toolkit: 'modern', theme: 'theme-material', packages: ['charts'], output: path.join('build', 'ext') }) ] ... };

@extjs/reactor-boilerplate

reactor-boilerplate