...
This is where JSX can truly shine - rather than a mess of e('div', {}, e('div', {}, e('div', {}, ... )))
, we can use the cleaner, more familiar syntax of <div><div><div>...</div></div></div>
Below, I have provided a few test files. To see these examples in action, simply copy them to your local machine.
You can then view them by navigating a browser to file:///path/to/example.index.html
Custom Components Written without JSX
...
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<!-- Load Bootstrap CSS from CDN --> <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> <!-- Load React from CDN --> <!-- Note: when deploying to production, replace "development.js" with "production.min.js". --> <script src="//unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="//unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <div id="react_test">Component failed to load</div> <!-- STOP! The contents of the following script tag can be compiled with the debugger console, located here: https://babeljs.io/en/repl --> <!-- See react-jsx-compiled.index.html for compiled browser-ready results --> <script> 'use strict'; let e = window.React.createElement; let ReactDOM = window.ReactDOM; // TypeScript used here - feels like a more formal JavaScript class MetadataTable extends React.Component { constructor(props) { super(props); this.state = { headers: [ { key: 'name', label: 'Name' }, { key: 'type', label: 'Type' }, { key: 'lastUpdated', label: 'Last Updated' }, { key: 'value', label: 'Value' }, { key: 'additionalActions', label: 'More...' } ], data: [ { 'name': 0, 'value': 'hello'}, { 'name': 1, 'value': 'react'}, { 'name': 2, 'value': 'with'}, { 'name': 3, 'value': 'jsx'}, ], newValue: '' }; } getTableHeaders() { let tableHeaders = []; for(let i = 0; i < this.state.headers.length; i++) { let header = this.state.headers[i]; let uniqueKey = 'table_header_' + header.key; // Push table header cells into the header row // Notice that we no longer return an HTML element here tableHeaders.push({ 'key': uniqueKey, 'width': (100 / this.state.headers.length).toString() + '%', 'label': header.label }); } // Accumulate and return table header data return tableHeaders; } getTableRowData() { let tableRows = []; for(let i = 0; i < this.state.data.length; i++) { let item = this.state.data[i]; let uniqueKey = 'table_row_data_' + i.toString(); let rowData = []; // Loop over selected headers to print table row values for(let j = 0; j < this.state.headers.length; j++) { let header = this.state.headers[j]; let uniqueKey = 'table_' + header.key.toString() + '_' + i.toString(); // Push table cell values into a "row" // Notice that we no longer return an HTML element here rowData.push({ 'key': uniqueKey, 'width': (100 / this.state.headers.length).toString() + '%', 'label': item[header.key] }); } // Push the row of cell data into the table // Notice that we no longer return an HTML element here tableRows.push({ key: uniqueKey, 'data': rowData }); } // Accumulate and return table row data return tableRows; } handleNewValueChange(event) { console.debug("OnChange Event:", event); this.setState({ 'newValue': event.target.value }); } addNew(event) { console.debug("OnClick Event:", event); let data = this.state.data; data.push({ 'name': this.state.data.length, 'value': this.state.newValue }); this.setState({ 'data': data }); this.setState({ 'newValue': '' }); } render() { // Re-fetch selected headers and row data let tableHeaders = this.getTableHeaders(); let tableRows = this.getTableRowData(); // Render the table data with React // NOTE: JSX syntax is returned - feels a bit like Scala return ( <div className='table-responsive'> <table className='table table-condensed table-hover'> <thead> <tr> {tableHeaders.map((item, i) => { // For each column header in tableHeaders return (<th key={item.key} width={item.width}>{item.label}</th>); })} </tr> </thead> <tbody> {tableRows.map((row, i) => { // For each row in tableRows return ( <tr key={row.key}> {row.data.map((cell, j) => { // For each cell in the row return (<td key={cell.key} width={cell.width}>{cell.label}</td>); })} </tr> ); })} <tr> <td> <input placeholder='Dummy text input...' value={this.state.newValue} onChange={this.handleNewValueChange} /> </td> <td> <button className='btn btn-xs btn-primary' onClick={(event) => { this.addNew(event, this.state.newValue) }}>Add new</button> </td> </tr> </tbody> </table> </div> ); } } console.log("Rendering!"); let domContainer = document.querySelector('#react_test'); ReactDOM.render( <MetadataTable />, domContainer ); console.log("Rendered!"); </script> |
...
Compilation Step
JSX requires us to compile down to JavaScript - to do this, we simply pass our source code through a Babel compiler.
...
The result of the compilation might look as follows - Note that the JSX parts below have been replaced with React.createElement()
by the compiler
This compiled output can be then , and can be immediately consumed by your browser:
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
<!-- Load Bootstrap CSS from CDN --> <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> <!-- Load React from CDN --> <!-- Note: when deploying to production, replace "development.js" with "production.min.js". --> <script src="//unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="//unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <div id="react_test">Component failed to load</div> <!-- STOP! The contents of the following script tag were compiled using the debugger console, located here: https://babeljs.io/en/repl --> <!-- See react-jsx.index.html for original compilation source --> <script> 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var e = window.React.createElement; var ReactDOM = window.ReactDOM; // TypeScript used here - feels like a more formal JavaScript var MetadataTable = function (_React$Component) { _inherits(MetadataTable, _React$Component); function MetadataTable(props) { _classCallCheck(this, MetadataTable); var _this = _possibleConstructorReturn(this, (MetadataTable.__proto__ || Object.getPrototypeOf(MetadataTable)).call(this, props)); _this.state = { headers: [{ key: 'name', label: 'Name' }, { key: 'type', label: 'Type' }, { key: 'lastUpdated', label: 'Last Updated' }, { key: 'value', label: 'Value' }, { key: 'additionalActions', label: 'More...' }], data: [{ 'name': 0, 'value': 'hello' }, { 'name': 1, 'value': 'react' }, { 'name': 2, 'value': 'with' }, { 'name': 3, 'value': 'jsx' }], newValue: '' }; return _this; } _createClass(MetadataTable, [{ key: 'getTableHeaders', value: function getTableHeaders() { var tableHeaders = []; for (var i = 0; i < this.state.headers.length; i++) { var header = this.state.headers[i]; var uniqueKey = 'table_header_' + header.key; // Push table header cells into the header row //tableHeaders.push(e('th', { 'key': uniqueKey, 'width': `${100 / this.state.headers.length}%` }, `${header.label}`)); tableHeaders.push({ 'key': uniqueKey, 'width': (100 / this.state.headers.length).toString() + '%', 'label': header.label }); } // Accumulate and return table header data return tableHeaders; } }, { key: 'getTableRowData', value: function getTableRowData() { var tableRows = []; for (var i = 0; i < this.state.data.length; i++) { var item = this.state.data[i]; var uniqueKey = 'table_row_data_' + i.toString(); var rowData = []; // Loop over selected headers to print table row values for (var j = 0; j < this.state.headers.length; j++) { var header = this.state.headers[j]; var _uniqueKey = 'table_' + header.key.toString() + '_' + i.toString(); // Push table cell values into a "row" //rowData.push(e('td', { 'key': uniqueKey, 'width': `${100 / this.state.headers.length}%`}, `${item[header.key]}`)); rowData.push({ 'key': _uniqueKey, 'width': (100 / this.state.headers.length).toString() + '%', 'label': item[header.key] }); } // Push the row of cell data into the table //tableRows.push(e('tr', { 'key': uniqueKey }, rowData)); tableRows.push({ key: uniqueKey, 'data': rowData }); } // Accumulate and return table row data return tableRows; } }, { key: 'handleNewValueChange', value: function handleNewValueChange(event) { console.debug("OnChange Event:", event); this.setState({ 'newValue': event.target.value }); } }, { key: 'addNew', value: function addNew(event) { console.debug("OnClick Event:", event); var data = this.state.data; data.push({ 'name': this.state.data.length, 'value': this.state.newValue }); this.setState({ 'data': data }); this.setState({ 'newValue': '' }); } }, { key: 'render', value: function render() { var _this2 = this; // Re-fetch selected headers and row data var tableHeaders = this.getTableHeaders(); var tableRows = this.getTableRowData(); // Render the table data with React // NOTE: JSX syntax is returned - feels a bit like Scala return React.createElement( 'div', { className: 'table-responsive' }, React.createElement( 'table', { className: 'table table-condensed table-hover' }, React.createElement( 'thead', null, React.createElement( 'tr', null, tableHeaders.map(function (item, i) { // For each column header in tableHeaders return React.createElement( 'th', { key: item.key, width: item.width }, item.label ); }) ) ), React.createElement( 'tbody', null, tableRows.map(function (row, i) { // For each row in tableRows return React.createElement( 'tr', { key: row.key }, row.data.map(function (cell, j) { // For each cell in the row return React.createElement( 'td', { key: cell.key, width: cell.width }, cell.label ); }) ); }), React.createElement( 'tr', null, React.createElement( 'td', null, React.createElement('input', { placeholder: 'Dummy text input...', value: this.state.newValue, onChange: this.handleNewValueChange }) ), React.createElement( 'td', null, React.createElement( 'button', { className: 'btn btn-xs btn-primary', onClick: function onClick(event) { _this2.addNew(event, _this2.state.newValue); } }, 'Add new' ) ) ) ) ) ); } }]); return MetadataTable; }(React.Component); console.log("Rendering!"); var domContainer = document.querySelector('#react_test'); ReactDOM.render(React.createElement(MetadataTable, null), domContainer); console.log("Rendered!"); </script> |
...