EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4

Post on 24-Jan-2017

99 views 0 download

Transcript of EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4

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