add rt-stateless option for stateless functional components (fixes #75)

This commit is contained in:
Omer Ganim 2016-05-15 16:28:47 +03:00
parent 63be2c9968
commit 5b6eb7222c
6 changed files with 44 additions and 6 deletions

View File

@ -375,6 +375,29 @@ define([
});
```
## stateless components
Since React v0.14, [React allows defining a component as a pure function of its props](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions).
To enable creating a stateless component using react templates, add the `rt-stateless` attribute to the template's root element.
Using `rt-stateless` generates a stateless functional component instead of a render function.
The resulting function receives a `props` parameter to be used in the template instead of `this.props`.
###### Sample:
```html
<div rt-stateless>Hello {props.person}</div>
```
###### Compiled:
```html
define([
'react',
'lodash'
], function (React, _) {
'use strict';
return function (props) {
return React.createElement('div', {}, 'Hello ', props.person);
};
});
```
## event handlers
React event handlers accept function references inside of {}, such as `onClick="{this.myClickHandler}"`. When functions are not needed, lambda notation can be used,
which will create a React template that creates a function for the included code. There is no performance impact, as the function created is bound to the context instead of being recreated.

View File

@ -35,10 +35,10 @@ _.forEach(reactSupportedAttributes, attributeReactName => {
const htmlSelfClosingTags = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
const templateAMDTemplate = _.template("define(<%= name ? '\"'+name + '\", ' : '' %>[<%= requirePaths %>], function (<%= requireNames %>) {\n'use strict';\n <%= injectedFunctions %>\nreturn function(){ return <%= body %>};\n});");
const templateCommonJSTemplate = _.template("'use strict';\n<%= vars %>\n\n<%= injectedFunctions %>\nmodule.exports = function(){ return <%= body %>};\n");
const templateES6Template = _.template('<%= vars %>\n\n<%= injectedFunctions %>\nexport default function(){ return <%= body %>}\n');
const templatePJSTemplate = _.template(`var <%= name %> = function () {
const templateAMDTemplate = _.template("define(<%= name ? '\"'+name + '\", ' : '' %>[<%= requirePaths %>], function (<%= requireNames %>) {\n'use strict';\n <%= injectedFunctions %>\nreturn function(<%= statelessProps %>){ return <%= body %>};\n});");
const templateCommonJSTemplate = _.template("'use strict';\n<%= vars %>\n\n<%= injectedFunctions %>\nmodule.exports = function(<%= statelessProps %>){ return <%= body %>};\n");
const templateES6Template = _.template('<%= vars %>\n\n<%= injectedFunctions %>\nexport default function(<%= statelessProps %>){ return <%= body %>}\n');
const templatePJSTemplate = _.template(`var <%= name %> = function (<%= statelessProps %>) {
<%= injectedFunctions %>
return <%= body %>
};

View File

@ -54,6 +54,7 @@ const includeNode = 'rt-include';
const includeSrcAttr = 'src';
const requireAttr = 'rt-require';
const importAttr = 'rt-import';
const statelessAttr = 'rt-stateless';
const reactTemplatesSelfClosingTags = [includeNode];
@ -530,6 +531,9 @@ function parseAndConvertHtmlToReact(html, context) {
handleImport(tag, context);
} else if (firstTag === null) {
firstTag = tag;
if (_.hasIn(tag, ['attribs', statelessAttr])) {
context.stateless = true;
}
} else {
throw RTCodeError.build(context, tag, 'Document should have no more than a single root element');
}
@ -566,7 +570,8 @@ function convertRT(html, reportContext, options) {
requireNames,
requirePaths,
vars,
name: options.name
name: options.name,
statelessProps: context.stateless ? 'props' : ''
};
let code = templates[options.modules](data);
if (options.modules !== 'typescript' && options.modules !== 'jsrt') {

1
test/data/stateless.rt Normal file
View File

@ -0,0 +1 @@
<div rt-stateless>Hello {props.person}</div>

View File

@ -0,0 +1,9 @@
define([
'react',
'lodash'
], function (React, _) {
'use strict';
return function (props) {
return React.createElement('div', {}, 'Hello ', props.person);
};
});

View File

@ -29,7 +29,7 @@ module.exports = {
});
test('conversion test', t => {
const files = ['div.rt', 'test.rt', 'repeat.rt', 'inputs.rt', 'virtual.rt'];
const files = ['div.rt', 'test.rt', 'repeat.rt', 'inputs.rt', 'virtual.rt', 'stateless.rt'];
testFiles(t, files);
});