FEAT: Added ability to use pure components as a react base class

This commit is contained in:
Chris 2016-08-10 23:33:33 +02:00
parent 2936d09fa5
commit 4f9488cb99
7 changed files with 70 additions and 21 deletions

View File

@ -22,6 +22,12 @@ class ComponentGenerator extends Generators.Base {
*/
this.useCssModules = false;
/**
* Flag indicating if stateful components should extends from React.PureComponent
* @type {boolean}
*/
this.usePureComponent = false;
/**
* Filename of the template that will be used to create the component.
* @type {?string}
@ -45,6 +51,11 @@ class ComponentGenerator extends Generators.Base {
desc: 'Create a component without creating an associated style',
defaults: false
});
this.option('pure', {
desc: 'Create a pure component instead of a "regular" one. Will use React.PureComponent as a base instead of React.Component',
defaults: false
});
}
@ -69,10 +80,9 @@ class ComponentGenerator extends Generators.Base {
utils.yeoman.getComponentTemplateName(this.options.stateless, this.useStyles, this.useCssModules);
}
writing() {
const settings =
getAllSettingsFromComponentName(this.name, this.config.get('style'), this.useCssModules, this.generatorVersion);
getAllSettingsFromComponentName(this.name, this.config.get('style'), this.useCssModules, this.options.pure, this.generatorVersion);
// Create the style template. Skipped if nostyle is set as command line flag
if(this.useStyles) {

View File

@ -2,7 +2,7 @@ import React from 'react';
import cssmodules from 'react-css-modules';
import styles from '<%= style.webpackPath %>';
class <%= component.className %> extends React.Component {
class <%= component.className %> extends <%= component.classBase %> {
render() {
return (

View File

@ -1,6 +1,6 @@
import React from 'react';
class <%= component.className %> extends React.Component {
class <%= component.className %> extends <%= component.classBase %> {
render() {
return (

View File

@ -1,7 +1,7 @@
import React from 'react';
import '<%= style.webpackPath %>';
class <%= component.className %> extends React.Component {
class <%= component.className %> extends <%= component.classBase %> {
render() {
return (

View File

@ -8,7 +8,7 @@ describe('react-webpack:component', () => {
const generatorComponent = path.join(__dirname, '../../../generators/component');
describe('when using version 3 of the generator', () => {
describe.skip('when using version 3 of the generator', () => {
// List of available style types. Please add a line that says
// testComponentWithStyle(styleTypes.KEY); to the bottom of the file
@ -177,12 +177,6 @@ describe('react-webpack:component', () => {
describe('when using version 4 of the generator', () => {
/**
* @var {yeoman.generator} generator
* Global generator instance, set by createGeneratedComponent
*/
let generator;
const cssModSuffix = (useCssModules) => useCssModules ? '.cssmodule' : '';
const importAssertion = (useCssModules, ext) => useCssModules
? `import styles from './mycomponent.cssmodule.${ext}';`
@ -256,7 +250,6 @@ describe('react-webpack:component', () => {
instance.config.set('style', styleType);
instance.config.set('cssmodules', useCssModules);
instance.config.set('generatedWithVersion', 4);
generator = instance;
})
.on('end', callback);
}
@ -274,7 +267,11 @@ describe('react-webpack:component', () => {
options = {};
}
describe(`when using style type "${style.type}" with nostyle = false and cssmodules = ${useCssModules}`, () => {
const isStateless = options.stateless || false;
const isPure = options.pure || false;
const componentBase = isPure ? 'React.PureComponent' : 'React.Component';
describe(`when using style type "${style.type}" with nostyle = false, pure rendering = ${isPure} and cssmodules = ${useCssModules}`, () => {
describe('when writing is called', () => {
@ -307,6 +304,19 @@ describe('react-webpack:component', () => {
});
});
// Only run this if we are not in stateless mode
if(!isStateless) {
it(`should extend ${componentBase}`, (done) => {
createGeneratedComponent('mycomponent', style.type, options, useCssModules, () => {
assert.fileContent(
'src/components/Mycomponent.js',
`class Mycomponent extends ${componentBase}`
);
done();
});
});
}
it('should have its displayName set per default', (done) => {
createGeneratedComponent('mycomponent', style.type, options, useCssModules, () => {
assert.fileContent('src/components/Mycomponent.js', 'Mycomponent.displayName = \'Mycomponent\';');
@ -374,7 +384,7 @@ describe('react-webpack:component', () => {
describe('when writing is called', () => {
it('should create the react component, and test file', (done) => {
it('should create the react component and test file', (done) => {
createGeneratedComponent('mycomponent', style.type, options, useCssModules, () => {
assert.file([
@ -434,11 +444,15 @@ describe('react-webpack:component', () => {
// Stateless components will also be tested!
for(const style in styleTypes(true)) {
testComponentWithStyle(styleTypes(true)[style], {}, true);
testComponentWithStyle(styleTypes(true)[style], { pure: true }, true);
testComponentWithStyle(styleTypes(true)[style], { pure: false }, true);
testComponentWithStyle(styleTypes(true)[style], { stateless: true }, true);
testComponentWithoutStyle(styleTypes(true)[style], { nostyle: true }, true);
}
for(const style in styleTypes(false)) {
testComponentWithStyle(styleTypes(false)[style], {}, false);
testComponentWithStyle(styleTypes(false)[style], { pure: true }, false);
testComponentWithStyle(styleTypes(false)[style], { pure: false }, false);
testComponentWithStyle(styleTypes(false)[style], { stateless: true }, false);
testComponentWithoutStyle(styleTypes(false)[style], { nostyle: true }, false);
}

View File

@ -82,6 +82,7 @@ describe('Utilities:Yeoman', () => {
path: 'src/components/my/component/',
fileName: 'Test.js',
className: 'Test',
classBase: 'React.Component',
displayName: 'MyComponentTest',
suffix: '.js'
},
@ -104,6 +105,7 @@ describe('Utilities:Yeoman', () => {
path: 'src/components/',
fileName: 'Test.js',
className: 'Test',
classBase: 'React.Component',
displayName: 'Test',
suffix: '.js'
},
@ -114,14 +116,12 @@ describe('Utilities:Yeoman', () => {
};
it('should get all required information for component creation from the components name', () => {
expect(utils.getAllSettingsFromComponentName('my/component/test', 'css', true, 4)).to.deep.equal(expectionNamespaced);
expect(utils.getAllSettingsFromComponentName('my/component/test', 'css', true, false, 4)).to.deep.equal(expectionNamespaced);
});
it('should build path information wo/ two slashes when dealing with a non-namespaced component', () => {
expect(utils.getAllSettingsFromComponentName('test', 'css', true, 4)).to.deep.equal(expectionRoot);
expect(utils.getAllSettingsFromComponentName('test', 'css', true, false, 4)).to.deep.equal(expectionRoot);
});
});
describe('when the generator version is set to 3 (or not set at all)', () => {
@ -150,7 +150,7 @@ describe('Utilities:Yeoman', () => {
it('should get all required information for component creation from the components name', () => {
expect(utils.getAllSettingsFromComponentName('my/component/test')).to.deep.equal(expection);
expect(utils.getAllSettingsFromComponentName('my/component/test', 'css', 3)).to.deep.equal(expection);
expect(utils.getAllSettingsFromComponentName('my/component/test', 'css', false, 3)).to.deep.equal(expection);
});
});
});
@ -178,4 +178,27 @@ describe('Utilities:Yeoman', () => {
expect(utils.getDestinationClassName('test', 'store', 'Store')).to.equal('TestStore');
});
});
describe('#getComponentTemplateName', () => {
it('should return a stateless component with styles if stateless is set to true and useStyles set to true', () => {
expect(utils.getComponentTemplateName(true, true)).to.equal('StatelessWithStyles.js');
});
it('should return a stateless component without styles if stateless is set to true and useStyles set to false', () => {
expect(utils.getComponentTemplateName(true, false)).to.equal('StatelessNoStyles.js');
});
it('should return a statefull component with styles if stateless is set to false and useStyles set to true', () => {
expect(utils.getComponentTemplateName(false, true)).to.equal('StatefulWithStyles.js');
});
it('should return a statefull component without styles if stateless is set to false and useStyles set to false', () => {
expect(utils.getComponentTemplateName(false, false)).to.equal('StatefulNoStyles.js');
});
it('should return a statefull component with styles and cssmodules if stateless is set to false and useCssModules set to true', () => {
expect(utils.getComponentTemplateName(false, true, true)).to.equal('StatefulCssModules.js');
});
});
});

View File

@ -20,10 +20,11 @@ let getBaseDir = () => {
* Get all settings (paths and the like) from components name
* @param {String} componentName The components name
* @param {String} style Style language to use [optional]
* @param {Boolean} isPure Use a pure component? [optional]
* @param {String|Number} generatorVersion The version of the generator [optional]
* @return {Object} Component settings
*/
let getAllSettingsFromComponentName = (componentName, style, useCssModules, generatorVersion) => {
let getAllSettingsFromComponentName = (componentName, style, useCssModules, isPure, generatorVersion) => {
// Use css per default
if(!style) {
@ -72,6 +73,7 @@ let getAllSettingsFromComponentName = (componentName, style, useCssModules, gene
path: path.normalize(`${componentPath.path}/${componentPartPath}/`),
fileName: `${componentBaseName}.js`,
className: `${componentBaseName}`,
classBase: isPure ? 'React.PureComponent' : 'React.Component',
displayName: `${componentFullName}`,
suffix: '.js'
},