The @extjs/reactor package makes it easy to use Ext JS components in your React app.
- Ext JS 6.2+
- Sencha Cmd 6.2+
- React 15.4.0+ (peer dependency)
# Be sure to install react>=15.4.0 before
npm install --save @extjs/reactor
npm install --save-dev @extjs/reactor-webpack-plugin @extjs/reactor-babel-plugin
We recommend you start by cloning the boilerplate project and following the instructions there.
The boilerplate project uses Ext JS 6 with the modern toolkit. There is also a boilerplate project using the classic toolkit.
First, install the reactor. We recommend doing this in your index.js file (your webpack entry point). This only needs to be done once in your app.
import { install } from '@extjs/reactor';
install();
If you choose to use an Ext JS component at the root of your app to handle the main layout, set the viewport
option to true
when installing the Ext JS renderer. This will set the height of the html, body, and react root element to 100% so that your Ext JS root component will fill the full screen. For example:
install({ viewport: true });
The @extjs/reactor
package exports a function called reactify
that creates a React component for any Ext JS component class. Here's a minimal React app that renders an Ext.Panel:
import React from 'react';
import ReactDOM from 'react-dom';
import { install, reactify } from '@extjs/reactor';
// Install the Ext JS custom renderer
install();
// Create a React component to wrap Ext.Panel
const Panel = reactify('panel');
// When Ext JS loads, initialize our React app
Ext.onReady(() => {
ReactDOM.render(
(
<Panel title="React Ext JS">
Hello World!
</Panel>
),
document.getElementById('root')
);
});
The reactify function allows you to create React components for multiple xtypes at once using array destructuring:
import { reactify } from '@extjs/reactor';
const [ Panel, Grid ] = reactify('panel', 'grid');
If you're using Babel, we recommend installing @extjs/reactor-babel-plugin, which allows you to do this instead...
import { Panel, Grid } from '@extjs/reactor/modern';
... and so our Hello World app becomes ...
import React from 'react';
import ReactDOM from 'react-dom';
import { install } from '@extjs/reactor';
import { Panel } from '@extjs/reactor/modern';
// Install the Ext JS custom renderer
install();
// When Ext JS loads, initialize our React app
Ext.onReady(() => {
ReactDOM.render(
(
<Panel title="React Ext JS">
Hello World!
</Panel>
),
document.getElementById('root')
);
});
All of the examples below leverage the @extjs/reactor-babel-plugin to achieve this more concise syntax.
When using the classic toolkit, your import statements would look like:
import { Grid } from '@extjs/reactor/classic';
React props are converted to Ext JS configs. Here's a typical use of an Ext.grid.Grid:
import React, { Component } from 'react';
import { Grid } from '@extjs/reactor/modern';
export default class MyComponent extends Component {
render() {
return (
<Grid
plugins={[
{ type: 'columnresizing' }
]}
columns={[
{ text: 'Name', dataIndex: 'name' },
{ text: 'Email', dataIndex: 'email' }
]}
store={{
fields: ['name', 'email'],
data: [
{ name: 'Tim Smith', email: '[email protected]' },
{ name: 'Jill Lindsey', email: '[email protected]' }
]
}}
/>
)
}
}
Any prop starting with "on" followed by a capital letter is automatically converted to an Ext JS event listener. Since Ext JS events are all lower-case, case is not preserved. You're free to use camel-case, which is common in React.
import React, { Component } from 'react';
import { Slider } from '@extjs/reactor/modern';
export default function MyComponent() {
return (
<Slider
minValue={0}
maxValue={100}
onChange={(slider, value) => console.log(`Value set to ${value}`)}
/>
)
}
You can also use a listeners object as is common in traditional Ext JS:
import React, { Component } from 'react';
import { Slider } from '@extjs/reactor/modern';
export default function MyComponent() {
return (
<Slider
minValue={0}
maxValue={100}
listeners={{
change: (slider, value) => console.log(`Value set to ${value}`)
}}
/>
)
}
Refs point to Ext JS component instances:
import React, { Component } from 'react';
import { Slider } from '@extjs/reactor/modern';
export default class MyComponent {
render() {
return (
<Slider
ref="slider"
minValue={0}
maxValue={100}
onChange={() => this.onChange()}
/>
)
}
onChange() {
console.log('Slider value', this.refs.slider.getValue()); // this.refs.slider is an Ext.slider.Slider
}
}
When using the Classic Toolkit, any component with a dock
prop is automatically added to (dockedItems)[http://docs.sencha.com/extjs/6.2.0/classic/Ext.panel.Panel.html#cfg-dockedItems] for your convenience.
Here is an example which docks a toolbar above a grid:
import { Grid, Panel, Toolbar, TextField } from '@extjs/reactor/classic';
function MyComponent(props) {
return (
<Panel layout="fit">
<Toolbar dock="top">
<TextField emptyText="Search..." flex={1}/>
</Toolbar>
<Grid>...</Grid>
</Panel>
)
}
HTML elements and other non-Ext JS React components are wrapped in an Ext.Component instance when they appear within an Ext JS Component. This is allows Ext JS layouts to work with non-Ext JS components. For example...
<Panel layout="hbox">
<div>left</div>
<div>right</div>
</Panel>
... will result in two divs side-by-side. The component structure created is equivalent to:
Ext.create({
xtype: 'panel',
layout: 'hbox'
items: [{
xtype: 'component',
html: '<div>left</div>'
}, {
xtype: 'component',
html: '<div>right</div>'
}]
});
When an Ext JS component contains only text, that text will be set as the html config of the component. For example...
<Panel>Hello World!</Panel>
... results in ...
Ext.create({
xtype: 'panel',
html: 'Hello World!'
});
Select your toolkit, theme, and packages using [@extjs/reactor-webpack-plugin]. The plugin scans your code and only includes the classes you need in the final bundle. Here's an example:
const ExtJSReactWebpackPlugin = require('@extjs/reactor-webpack-plugin');
module.exports = {
...
plugins: [
new ExtJSReactWebpackPlugin({
sdk: 'ext', // location of Ext JS SDK
theme: 'theme-material',
packages: ['charts']
})
]
...
}
If you're using Babel, we recommend adding @extjs/reactor-babel-plugin to your .babelrc. For example:
{
"presets": ["es2015", "react"],
"plugins": ["@extjs/reactor-babel-plugin"]
}
This is a monorepo that uses lerna. After cloning, run npm install
then lerna bootstrap
to install dependencies.
- @extjs/reactor - A custom React renderer that lets you to use any Ext JS xtype as a JSX tag
- @extjs/reactor-webpack-plugin - Integrates Webpack with Sencha Cmd to produce optimized builds of Ext JS
- @extjs/reactor-babel-plugin - Allows you to load reactified Ext JS components using ES6 import syntax.
- @extjs/reactor-boilerplate - An example project using React, Webpack, and Ext JS 6 with the modern toolkit.
- @extjs/reactor-classic-boilerplate - An example project using React, Webpack, and Ext JS 6 with the classic toolkit.
We'd love to accept patches and new boilerplates. Before we can take them, we need you to sign this CLA.
Once we receive it, we'll be able to accept your pull requests.
- Submit an issue describing your proposed change.
- The repo owner will respond to your issue promptly.
- If your proposed change is accepted, fork the repo, develop and test your code changes.
- Submit a pull request.