Post on 24-Jan-2017
Copyright © 2016 M/Gateway Developments Ltd
EWD 3 Training CoursePart 40
Building a React.js-based QEWD Application
(d) Using sub-components
Rob TweedDirector, M/Gateway Developments Ltd
Twitter: @rtweed
Copyright © 2016 M/Gateway Developments Ltd
Still a very simple app
• Our demo doesn't do very much• Just a single top-level component
– MainPage.js• Plus its associated controller module
• React.js apps are usually a hierarchy of components– Let's start extending our demo
Copyright © 2016 M/Gateway Developments Ltd
A More Typical Scenario
Main Page
Title / Banner Login Form Main Menu Content
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;
var MainPage = React.createClass({getInitialState: function() {
return {status: 'initial',
}},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (// sub-component to handle the Title / banner// sub-component to handle a log-in form// sub-component to handle a main menu// sub-component to handle the main display of content
);}
});module.exports = MainPage;
MainPage.js
How it would be implemented:
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;
var MainPage = React.createClass({getInitialState: function() {
return {status: 'initial',
}},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},
return (// sub-component to handle the Title / banner// sub-component to handle the main display of content
);});module.exports = MainPage;
MainPage.js
Let's just take 2 for now tokeep it simple:
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;
var MainPage = React.createClass({getInitialState: function() {
return {status: 'initial',
}},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<Title /><Content />
);}
});module.exports = MainPage;
MainPage.js
Let's just take 2 for now tokeep it simple:
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var Content = require('./Content');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<Title /><Content />
);}
});module.exports = MainPage;
MainPage.js
These must beloaded as modules
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var Content = require('./Content');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<Title
controller = {controller} /><Content
controller = {controller} />
);}
});module.exports = MainPage;
MainPage.js
We need to pass thecontroller object into them:
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var Content = require('./Content');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<Title
controller = {controller} /><Content
controller = {controller} />
);}
});module.exports = MainPage;
MainPage.js
The child componentsare now going to
do the work
The Main Page will nolonger have any
dynamic behaviour assuch, but we'll leave
the controller in place,but simplify it
Copyright © 2016 M/Gateway Developments Ltd
MainPage-controller.jsmodule.exports = function (controller, component) {controller.log = true;return controller;
};
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var Content = require('./Content');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<Title
controller = {controller} /><Content
controller = {controller} />
);}
});module.exports = MainPage;
MainPage.js
We'll also leavethis state variable
in place
It might come inuseful later
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<Title
controller = {controller} />
);}
});module.exports = MainPage;
MainPage.js
So let's createThe first
Sub-component:
<Title />
Copyright © 2016 M/Gateway Developments Ltd
<Title /> Componentvar React = require('react');var heading = 'My QEWD React Demo';var Title = React.createClass({
render: function() {return (<h2>{heading}</h2>
);}
});
module.exports = Title;
Copyright © 2016 M/Gateway Developments Ltd
<Title /> Componentvar React = require('react');var heading = 'My QEWD React Demo';var Title = React.createClass({
render: function() {return (<h2>{heading}</h2>
);}
});
module.exports = Title;
This doesn't require thecontroller object for its
current behaviour
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {return (<Title
controller = {controller} />
);}
});module.exports = MainPage;
MainPage.js
But we'll still passin the controller
for now.
We might need itlater
Copyright © 2016 M/Gateway Developments Ltd
<Title /> Componentvar React = require('react');var heading = 'My QEWD React Demo';var Title = React.createClass({
render: function() {return (<h2>{heading}</h2>
);}
});
module.exports = Title;
If we did want to use it, itwould be referenced as
this.props.controller
Copyright © 2016 M/Gateway Developments Ltd
<Title /> Componentvar React = require('react');var heading = 'My QEWD React Demo';var Title = React.createClass({
render: function() {return (<h2>{heading}</h2>
);}
});
module.exports = Title;
Save as:
~/qewd/www/react-demo1/Title.js
Copyright © 2016 M/Gateway Developments Ltd
Re-bundle and try it again
Copyright © 2016 M/Gateway Developments Ltd
Now let's add the Content Component
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var Content = require('./Content');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<Title
controller = {controller} /><Content
controller = {controller} />
);}
});module.exports = MainPage;
MainPage.js
Add the ContentComponent…
Copyright © 2016 M/Gateway Developments Ltd
<Content /> Componentvar React = require('react');
var Content = React.createClass({
render: function() {return (<div>Content will go here...</div>
);}
});
module.exports = Content;
We'll keep it very simple for now
No dynamic behaviour yet
Copyright © 2016 M/Gateway Developments Ltd
<Content /> Componentvar React = require('react');
var Content = React.createClass({
render: function() {return (<div>Content will go here...</div>
);}
});
module.exports = Content;
Save as:
C:\ewd3\www\react-demo1\Content.js
Copyright © 2016 M/Gateway Developments Ltd
Re-bundle it
cd \ewd3\www\react-demo1
browserify -t [ babelify --compact false --presets [es2015 react] ] app.js > bundle.js
Copyright © 2016 M/Gateway Developments Ltd
You'll get an error![es2015 react] ] app.js > bundle.jsSyntaxError: C:/ewd3-react/www/react-demo3/MainPage.js: Adjacent JSX elements must be wrapped in an enclosing tag (21:6)
19 | controller = {controller}20 | />
> 21 | <Content| ^
22 | controller = {controller}23 | />24 | );
at Parser.pp.raise (C:\ewd3-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\location.js:22:13)
at Parser.pp.jsxParseElementAt (C:\ewd3-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\plugins\jsx\index.js:470:10)
Copyright © 2016 M/Gateway Developments Ltd
You'll get an error![es2015 react] ] app.js > bundle.jsSyntaxError: C:/ewd3-react/www/react-demo3/MainPage.js: Adjacent JSX elements must be wrapped in an enclosing tag (21:6)
19 | controller = {controller}20 | />
> 21 | <Content| ^
22 | controller = {controller}23 | />24 | );
at Parser.pp.raise (C:\ewd3-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\parser\location.js:22:13)
at Parser.pp.jsxParseElementAt (C:\ewd3-react\node_modules\babelify\node_modules\babel-core\node_modules\babylon\lib\plugins\jsx\index.js:470:10)
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var Content = require('./Content');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<Title
controller = {controller} /><Content
controller = {controller} />
);}
});module.exports = MainPage;
Check in MainPage.js
What's inside the returnmust only be a single
parent JSX tag
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var Content = require('./Content');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<Title
controller = {controller} /><Content
controller = {controller} />
);}
});module.exports = MainPage;
Check in MainPage.js
What's inside the returnmust only be a single
parent JSX tag
So we must put <Title>and <Content> inside
a parent tag
Copyright © 2016 M/Gateway Developments Ltd
"use strict"var React = require('react');var controller;var Title = require('./Title');var Content = require('./Content');var MainPage = React.createClass({
getInitialState: function() {return {
status: 'initial',}
},componentWillMount: function() {
controller = require('./MainPage-controller')(this.props.controller, this);},render: function() {
return (<div>
<Titlecontroller = {controller}
/><Content
controller = {controller} />
</div>);
}});module.exports = MainPage;
Check in MainPage.js
A <div> tag will do the job!
Copyright © 2016 M/Gateway Developments Ltd
Now it should re-bundle OK
cd \ewd3\www\react-demo1
browserify -t [ babelify --compact false --presets [es2015 react] ] app.js > bundle.js
Copyright © 2016 M/Gateway Developments Ltd
Try it again
And now we have ourtwo components working
properly
Copyright © 2016 M/Gateway Developments Ltd
Still just a simple app
• No dynamic behaviour• Not using the QEWD back-end• But we've now established the basic
patterns for React development with QEWD– The components we've created can be used
as convenient templates• In the next part of the course, we'll add
some dynamic behaviour