Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

332 views

Published on

This is part 38 of the EWD 3 Training Course. This presentation begins to explore in detail how to develop a React.js application that integrates with QEWD

Published in: Software
  • Be the first to comment

  • Be the first to like this

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

  1. 1. Copyright © 2016 M/Gateway Developments Ltd EWD 3 Training Course Part 38 Building a React.js-based QEWD Application (b) First steps in developing with React.js Rob Tweed Director, M/Gateway Developments Ltd Twitter: @rtweed
  2. 2. Copyright © 2016 M/Gateway Developments Ltd Here's our Main component ~/qewd/www/react-demo1/MainPage.js "use strict" var React = require('react'); var MainPage = React.createClass({ render: function() { console.log('rendering MainPage'); return ( <div> This is my test React.js Application </div> ); } }); module.exports = MainPage; Let's make it send a message to QEWD and return a response that we display
  3. 3. Copyright © 2016 M/Gateway Developments Ltd Here's our Main component ~/qewd/www/react-demo1/MainPage.js "use strict" var React = require('react'); var MainPage = React.createClass({ render: function() { console.log('rendering MainPage'); return ( <div> We'll display the returned message here </div> ); } }); module.exports = MainPage; Let's make it send a message To QEWD and return a response that we display
  4. 4. Copyright © 2016 M/Gateway Developments Ltd When and where to send a message? We're currently just using the component's render() function ~/qewd/www/react-demo1/MainPage.js "use strict" var React = require('react'); var MainPage = React.createClass({ render: function() { console.log('rendering MainPage'); return ( <div> This is my test React.js Application </div> ); } }); module.exports = MainPage;
  5. 5. Copyright © 2016 M/Gateway Developments Ltd When and where to send a message? To send a message to QEWD, we should use a React life-cycle method For example: componentWillMount() componentDidMount() ~/qewd/www/react-demo1/MainPage.js "use strict" var React = require('react'); var MainPage = React.createClass({ render: function() { console.log('rendering MainPage'); return ( <div> This is my test React.js Application </div> ); } }); module.exports = MainPage;
  6. 6. Copyright © 2016 M/Gateway Developments Ltd When and where to send a message? To send a message to QEWD, we should use a React life-cycle method For example: componentWillMount() Triggered before rendering takes place ~/qewd/www/react-demo1/MainPage.js "use strict" var React = require('react'); var MainPage = React.createClass({ render: function() { console.log('rendering MainPage'); return ( <div> This is my test React.js Application </div> ); } }); module.exports = MainPage;
  7. 7. Copyright © 2016 M/Gateway Developments Ltd When and where to send a message? To send a message to QEWD, we should use a React life-cycle method For example: componentDidMount() Triggered after rendering takes place ~/qewd/www/react-demo1/MainPage.js "use strict" var React = require('react'); var MainPage = React.createClass({ render: function() { console.log('rendering MainPage'); return ( <div> This is my test React.js Application </div> ); } }); module.exports = MainPage;
  8. 8. Copyright © 2016 M/Gateway Developments Ltd When and where to send a message? To send a message to QEWD, we should use a React life-cycle method For example: componentWillMount() Triggered before rendering takes place This would seem to be the obvious one to use in our example ~/qewd/www/react-demo1/MainPage.js "use strict" var React = require('react'); var MainPage = React.createClass({ render: function() { console.log('rendering MainPage'); return ( <div> This is my test React.js Application </div> ); } }); module.exports = MainPage;
  9. 9. Copyright © 2016 M/Gateway Developments Ltd componentWillMount() "use strict" var React = require('react'); module.exports = React.createClass({ componentWillMount: function() { // do something before it renders }, render: function() { console.log('rendering MainPage'); return ( <div> This is my test React.js Application </div> ); } }); module.exports = MainPage;
  10. 10. Copyright © 2016 M/Gateway Developments Ltd componentWillMount() The controller object is created from and extends the EWD object So to send a message, we invoke its send() method The controller was passed to our main component as a prop named controller, so we refer to it as this.props.controller "use strict" var React = require('react'); var MainPage = React.createClass({ componentWillMount: function() { this.props.controller.send({ type: 'testMessage', params: { foo: 'bar' } }); }, render: function() { console.log('rendering MainPage'); return ( <div> This is my test React.js Application </div> ); } }); module.exports = MainPage;
  11. 11. Copyright © 2016 M/Gateway Developments Ltd Re-bundle it cd ewd3wwwreact-demo1 browserify -t [ babelify --compact false --presets [es2015 react] ] app.js > bundle.js You must re-run Browserify (or WebPack) to create a new bundle.js file, every time you modify any component or module in your application
  12. 12. Copyright © 2016 M/Gateway Developments Ltd Try it Nothing seems to have happened!
  13. 13. Copyright © 2016 M/Gateway Developments Ltd But check the QEWD log.. worker 5036 received message: {"type":"testMessage","params":{"foo":"bar"},"toke n":"9e27f30e-7152-469b-90fe-d637e5e1d8db"} master process received response from worker 5036: {"type":"testMessage","finish ed":true,"message":{"error":"No handler defined for react-demo1 messages of type testMessage"}} *** handleMessage response {"type":"testMessage","finished":true,"message":{"err or":"No handler defined for react-demo1 messages of type testMessage"}} sending to socket /#nDzlXWbHSfB2zCT5AAAH Master process has finished processing response from worker process 5036 which i s back in available pool
  14. 14. Copyright © 2016 M/Gateway Developments Ltd So it did send a message • Nothing is showing in the browser because logging isn't enabled • Let's fix that….
  15. 15. Copyright © 2016 M/Gateway Developments Ltd Turn on logging This is the equivalent of EWD.log = true; "use strict" var React = require('react'); var MainPage = React.createClass({ componentWillMount: function() { this.props.controller.log = true; this.props.controller.send({ type: 'testMessage', params: { foo: 'bar' } }); }, render: function() { console.log('rendering MainPage'); return ( <div> This is my test React.js Application </div> ); } }); module.exports = MainPage;
  16. 16. Copyright © 2016 M/Gateway Developments Ltd Re-bundle it browserify -t [ babelify --compact false --presets [es2015 react] ] app.js > bundle.js
  17. 17. Copyright © 2016 M/Gateway Developments Ltd Try it Now we can see that the message was sent and a response received
  18. 18. Copyright © 2016 M/Gateway Developments Ltd Try it But we can also see that we're getting back an error Of course, that's because we haven't created a back-end handler module for this application
  19. 19. Copyright © 2016 M/Gateway Developments Ltd We'll fix that… ~/qewd/node_modules/react-demo1.js module.exports = { handlers: { testMessage: function(messageObj, session, send, finished) { finished({text: 'Welcome! The value of foo was ' + messageObj.params.foo}); } } }; It's just a standard QEWD back-end handler module
  20. 20. Copyright © 2016 M/Gateway Developments Ltd Try it again Now it's working But we're not displaying the response in the page yet
  21. 21. Copyright © 2016 M/Gateway Developments Ltd Displaying the message So how do we get the response message to display here? "use strict" var React = require('react'); var MainPage = React.createClass({ componentWillMount: function() { this.props.controller.log = true; this.props.controller.send({ type: 'testMessage', params: { foo: 'bar' } }); }, render: function() { console.log('rendering MainPage'); return ( <div> This is where we want to display the response message </div> ); } }); module.exports = MainPage;
  22. 22. Copyright © 2016 M/Gateway Developments Ltd We seem to have a problem • Look carefully at the browser's console log: react-demo1 registered sent: {"type":"testMessage","params":{"foo":"bar"}} rendering MainPage received: {"type":"testMessage","finished":true,"message":{"text":"Welcome! The value of foo was bar"}}
  23. 23. Copyright © 2016 M/Gateway Developments Ltd We seem to have a problem • Look carefully at the browser's console log: react-demo1 registered sent: {"type":"testMessage","params":{"foo":"bar"}} rendering MainPage received: {"type":"testMessage","finished":true,"message":{"text":"Welcome! The value of foo was bar"}} We sent the message to the back-end
  24. 24. Copyright © 2016 M/Gateway Developments Ltd We seem to have a problem • Look carefully at the browser's console log: react-demo1 registered sent: {"type":"testMessage","params":{"foo":"bar"}} rendering MainPage received: {"type":"testMessage","finished":true,"message":{"text":"Welcome! The value of foo was bar"}} But before the response was received
  25. 25. Copyright © 2016 M/Gateway Developments Ltd We seem to have a problem • Look carefully at the browser's console log: react-demo1 registered sent: {"type":"testMessage","params":{"foo":"bar"}} rendering MainPage received: {"type":"testMessage","finished":true,"message":{"text":"Welcome! The value of foo was bar"}} The Main Page render() function ran
  26. 26. Copyright © 2016 M/Gateway Developments Ltd We seem to have a problem • Look carefully at the browser's console log: react-demo1 registered sent: {"type":"testMessage","params":{"foo":"bar"}} rendering MainPage received: {"type":"testMessage","finished":true,"message":{"text":"Welcome! The value of foo was bar"}} The Main Page render() function ran ..and React gives us no way to prevent that
  27. 27. Copyright © 2016 M/Gateway Developments Ltd Displaying the message So how do we deal with this? "use strict" var React = require('react'); var MainPage = React.createClass({ componentWillMount: function() { this.props.controller.log = true; this.props.controller.send({ type: 'testMessage', params: { foo: 'bar' } }); }, render: function() { console.log('rendering MainPage'); return ( <div> This is where we want to display the response message </div> ); } }); module.exports = MainPage;
  28. 28. Copyright © 2016 M/Gateway Developments Ltd By using a state variable Have a conditional render() outcome dependent on the value of a state variable "use strict" var React = require('react'); var MainPage = React.createClass({ componentWillMount: function() { this.props.controller.log = true; this.props.controller.send({ type: 'testMessage', params: { foo: 'bar' } }); }, render: function() { console.log('rendering MainPage'); return ( <div> This is where we want to display the response message </div> ); } }); module.exports = MainPage;
  29. 29. Copyright © 2016 M/Gateway Developments Ltd By using a state variable The state variable is initialised with one value, causing an initial rendering "use strict" var React = require('react'); var MainPage = React.createClass({ componentWillMount: function() { this.props.controller.log = true; this.props.controller.send({ type: 'testMessage', params: { foo: 'bar' } }); }, render: function() { console.log('rendering MainPage'); return ( <div> Initial message....probably nothing at all </div> ); } }); module.exports = MainPage;
  30. 30. Copyright © 2016 M/Gateway Developments Ltd By using a state variable When the response is received change the state variable value and make the render() function now display the response message "use strict" var React = require('react'); var MainPage = React.createClass({ componentWillMount: function() { this.props.controller.log = true; this.props.controller.send({ type: 'testMessage', params: { foo: 'bar' } }); }, render: function() { console.log('rendering MainPage'); return ( <div> Welcome! The value of foo was bar </div> ); } }); module.exports = MainPage;
  31. 31. Copyright © 2016 M/Gateway Developments Ltd Do the following… "use strict" var React = require('react'); var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; this.props.controller.send({ type: 'testMessage', params: { foo: 'bar' } }); }, ...etc Create a state variable named status with and initial value of initial The getInitialState() method is provided by React for this purpose
  32. 32. Copyright © 2016 M/Gateway Developments Ltd Do the following… "use strict" var React = require('react'); var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; this.props.controller.send(message, function(responseObj) { // handle the returned response }); }, Modify the message- sending logic to include a response handler
  33. 33. Copyright © 2016 M/Gateway Developments Ltd Do the following… "use strict" var React = require('react'); var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { component.setState({status: responseObj.message.text}); }); }, Change the state variable and give it the value of the response text React provides this.setState for this purpose
  34. 34. Copyright © 2016 M/Gateway Developments Ltd Do the following… "use strict" var React = require('react'); var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { component.setState({status: responseObj.message.text}); }); }, We need to ensure the external value of this is correctly available within the callback's closure
  35. 35. Copyright © 2016 M/Gateway Developments Ltd That's the state variable working • Now we need to make the component's render() method conditional on its value…
  36. 36. Copyright © 2016 M/Gateway Developments Ltd Do the following… ..etc.. render: function() { console.log('rendering MainPage'); if (this.state.status === 'initial') { return ( <div></div> ); } else { return ( <div>{this.state.status}</div> ); } } ..etc So it now renders an empty div inititially
  37. 37. Copyright © 2016 M/Gateway Developments Ltd Do the following… ..etc.. render: function() { console.log('rendering MainPage'); if (this.state.status === 'initial') { return ( <div></div> ); } else { return ( <div>{this.state.status}</div> ); } } ..etc Then, when re-rendered, it displays the value of the state variable which should now contain the response text
  38. 38. Copyright © 2016 M/Gateway Developments Ltd Do the following… ..etc.. var component = this; this.props.controller.send(message, function(responseObj) { component.setState({status: responseObj.message.text}); }); }, render: function() { console.log('rendering MainPage'); if (this.state.status === 'initial') { return ( <div></div> ); } else { return ( <div>{this.state.status}</div> ); } } ..etc Re-rendering occurs automatically when the state variable value is changed within the response handler's callback function
  39. 39. Copyright © 2016 M/Gateway Developments Ltd Do the following… ..etc.. render: function() { console.log('rendering MainPage'); if (this.state.status === 'initial') { return ( <div></div> ); } else { return ( <div>{this.state.status}</div> ); } } ..etc Note how JSX variables are specified within curly braces
  40. 40. Copyright © 2016 M/Gateway Developments Ltd Try it again The returned message is now displayed in the page You may briefly see "Please wait" appearing during the registration process
  41. 41. Copyright © 2016 M/Gateway Developments Ltd Try it again Notice how MainPage Is rendered twice Once initially then again when the response is received
  42. 42. Copyright © 2016 M/Gateway Developments Ltd Which life-cycle method to use? "use strict" var React = require('react'); var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { component.setState({status: responseObj.message.text}); }); }, We used componentWillMount() which fires before our MainPage component is rendered.
  43. 43. Copyright © 2016 M/Gateway Developments Ltd Which life-cycle method to use? "use strict" var React = require('react'); var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentDidMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { component.setState({status: responseObj.message.text}); }); }, We could have used componentDidMount() However this would have slightly delayed sending the message to QEWD until after the initial render was completed
  44. 44. Copyright © 2016 M/Gateway Developments Ltd Keep state variables for state only?
  45. 45. Copyright © 2016 M/Gateway Developments Ltd "use strict" var React = require('react'); var displayText = ''; var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { displayText = responseObj.message.text; component.setState({status: 'updated'}); }); }, render: function() { console.log('rendering MainPage'); return ( <div>{displayText}</div> ); } }); module.exports = MainPage;
  46. 46. Copyright © 2016 M/Gateway Developments Ltd "use strict" var React = require('react'); var displayText = ''; var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { displayText = responseObj.message.text; component.setState({status: 'updated'}); }); }, render: function() { console.log('rendering MainPage'); return ( <div>{displayText}</div> ); } }); module.exports = MainPage; Use a simple variable for the display text, initially set to an empty string
  47. 47. Copyright © 2016 M/Gateway Developments Ltd "use strict" var React = require('react'); var displayText = ''; var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { displayText = responseObj.message.text; component.setState({status: 'updated'}); }); }, render: function() { console.log('rendering MainPage'); return ( <div>{displayText}</div> ); } }); module.exports = MainPage; The render() method is no longer conditional, but now simply displays the value of the displayText variable
  48. 48. Copyright © 2016 M/Gateway Developments Ltd "use strict" var React = require('react'); var displayText = ''; var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { displayText = responseObj.message.text; component.setState({status: 'updated'}); }); }, render: function() { console.log('rendering MainPage'); return ( <div>{displayText}</div> ); } }); module.exports = MainPage; The status State variable is Still initialised as before
  49. 49. Copyright © 2016 M/Gateway Developments Ltd "use strict" var React = require('react'); var displayText = ''; var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { displayText = responseObj.message.text; component.setState({status: 'updated'}); }); }, render: function() { console.log('rendering MainPage'); return ( <div>{displayText}</div> ); } }); module.exports = MainPage; The response handler now resets the value of the displayText variable to the received response text
  50. 50. Copyright © 2016 M/Gateway Developments Ltd "use strict" var React = require('react'); var displayText = ''; var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { displayText = responseObj.message.text; component.setState({status: 'updated'}); }); }, render: function() { console.log('rendering MainPage'); return ( <div>{displayText}</div> ); } }); module.exports = MainPage; And then changes the status state variable to some other arbitrary value
  51. 51. Copyright © 2016 M/Gateway Developments Ltd "use strict" var React = require('react'); var displayText = ''; var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { displayText = responseObj.message.text; component.setState({status: 'updated'}); }); }, render: function() { console.log('rendering MainPage'); return ( <div>{displayText}</div> ); } }); module.exports = MainPage; The state variable is now just being used as a trigger to force a re-render of the MainPage component
  52. 52. Copyright © 2016 M/Gateway Developments Ltd "use strict" var React = require('react'); var displayText = ''; var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { displayText = responseObj.message.text; component.setState({status: 'updated'}); }); }, render: function() { console.log('rendering MainPage'); return ( <div>{displayText}</div> ); } }); module.exports = MainPage; On the 1st render, displayText is an empty string so nothing appears in the browser
  53. 53. Copyright © 2016 M/Gateway Developments Ltd "use strict" var React = require('react'); var displayText = ''; var MainPage = React.createClass({ getInitialState: function() { return { status: 'initial', } }, componentWillMount: function() { this.props.controller.log = true; var message = { type: 'testMessage', params: { foo: 'bar' } }; var component = this; this.props.controller.send(message, function(responseObj) { displayText = responseObj.message.text; component.setState({status: 'updated'}); }); }, render: function() { console.log('rendering MainPage'); return ( <div>{displayText}</div> ); } }); module.exports = MainPage; But on the 2nd render, displayText now contains the returned response
  54. 54. Copyright © 2016 M/Gateway Developments Ltd Re-bundle and try it again It will run exactly the same as before
  55. 55. Copyright © 2016 M/Gateway Developments Ltd Separation of Concerns • Currently they aren't separated – The dynamic behaviour and its associated controlling logic is all included in the MainPage component – MainPage should ideally just describe the View logic
  56. 56. Copyright © 2016 M/Gateway Developments Ltd Separation of Concerns • Currently they aren't separated – The dynamic behaviour and its associated controlling logic is all included in the MainPage component – MainPage should ideally just describe the View logic • In the next part of this course we'll look at how we can separate things

×