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.

Building web applications with React (Jfokus)

101 views

Published on

Getting started with React is easy, but building real-world applications can be a bit harder. How do you go beyond the "Hello, World" stage to build applications that are ready for prime time?

In this workshop we'll cover modern JavaScript, "thinking the React way", interacting with data sources, error handling and many more topics. We'll use this to build a web application that is ready to shine. As a bonus, you'll learn some of the React internals that enable you to write better applications.

Published in: Software
  • Be the first to comment

  • Be the first to like this

Building web applications with React (Jfokus)

  1. 1. B R Maarten Mulders (@mthmulders)#reactworkshop
  2. 2. T M a short intro in React and JSX Starter — Work on your own task management app! discuss event handling, interacting with REST, state Main Course — Add behaviours to the app you've created discuss testing Dessert — Wrap-up Maarten Mulders (@mthmulders)#reactworkshop
  3. 3. R JSX Maarten Mulders (@mthmulders)#reactworkshop
  4. 4. “React is a library for declaratively building user interfaces using JavaScript and (optionally) XML. Maarten Mulders (@mthmulders)#reactworkshop
  5. 5. R No two-way data binding No templating language Just user interface (no routing, no HTTP client) Plain JavaScript (or add JSX, TypeScript, ...) Virtual DOM vs. actual DOM Maarten Mulders (@mthmulders)#reactworkshop
  6. 6. W JSX A syntax extension to JavaScript real XML, not a string of characters allows embedded expressions supports attributes Can be nested Automatic XSS prevention Needs to be transpiled to JavaScript e.g. React.createElement(...) Maarten Mulders (@mthmulders)#reactworkshop
  7. 7. E Elements can be regular DOM elements... (for now, but not for long) Hej! const element = <div>Hej!</div> ReactDOM.render(element, document.getElementById('app')); 1 2 Maarten Mulders (@mthmulders)#reactworkshop
  8. 8. A Elements can have attributes... Hej const element = <div id='foo'>Hej</div> ReactDOM.render(element, document.getElementById('app')); 1 2 Maarten Mulders (@mthmulders)#reactworkshop
  9. 9. ... but they can have different names than HTML attributes: Hej const element = <div className='red­text'>Hej</div> ReactDOM.render(element, document.getElementById('app')); 1 2 Maarten Mulders (@mthmulders)#reactworkshop
  10. 10. ... and they can behave differently: Hej const style = { color: 'red' }; const element = <div style={ style }>Hej</div> ReactDOM.render(element, document.getElementById('app')); 1 2 3 Maarten Mulders (@mthmulders)#reactworkshop
  11. 11. C “Reusable building blocks for composing user interfaces. Maarten Mulders (@mthmulders)#reactworkshop
  12. 12. S (F ) Function that takes props and returns a React element. Hi, Jfokus! const Greeter = (props) => <div>Hi, { props.name }!</div> ReactDOM.render(<Greeter name='Jfokus' />, document.getElementById('app')); 1 2 Maarten Mulders (@mthmulders)#reactworkshop
  13. 13. S Class that can store state; render() method returns a React element. Hi, Jfokus! class Greeter extends React.Component {    constructor(props) {        super(props)        // Usually you don't copy props into state        this.state = { name: props.name };    }    render() {        return <div>Hi, { this.state.name }!</div>;    } } ReactDOM.render(<Greeter name='Jfokus' />, document.getElementById('app')); 1 2 3 4 5 6 7 8 9 10 11 Maarten Mulders (@mthmulders)#reactworkshop
  14. 14. S R N Values must have a single root node x y const element = <><div>x</div><div>y</div></> ReactDOM.render(element, document.getElementById('app')); 1 2 Maarten Mulders (@mthmulders)#reactworkshop
  15. 15. T R Compose applications from (re-usable) components consistent verifiable & testable clear interface ⟶ single responsibility principle Maarten Mulders (@mthmulders)#reactworkshop
  16. 16. L D T Start with a mockup of what you want to build Inbox @Work @Home @Supermarket Learn React Build my first React app Add new task Add Task Learn React Due date April 13, 2020 Completed yes List Inbox Group exercise: identify component hierarchy Maarten Mulders (@mthmulders)#reactworkshop
  17. 17. G T D S Maarten Mulders (@mthmulders)#reactworkshop
  18. 18. L D T Start with a mockup of what you want to build Inbox @Work @Home @Supermarket Learn React Build my first React app Add new task Add Task Learn React Due date April 13, 2020 Completed yes List Inbox 1. Identify component hierarchy 2. Create skeleton of component hierarchy Use background or border colors to distinguish componentsMaarten Mulders (@mthmulders)#reactworkshop
  19. 19. S JSX Maarten Mulders (@mthmulders)#reactworkshop
  20. 20. E JSX 42 const answerToQuestionOfLife = 42; const askQuestionOfLife = () => answerToQuestionOfLife; const App = () => <div>{ askQuestionOfLife() }</div>; ReactDOM.render(<App/>, document.getElementById('app')); 1 2 3 4 5 6 Maarten Mulders (@mthmulders)#reactworkshop
  21. 21. C JSX Clapping hands... const ClapHands = () => <span>Clapping hands...</span>; const DryTears = () => <span>Drying tears...</span>; const App = ({ isHappy }) => <div>{ isHappy ? <ClapHands /> : <DryTears /> }</div>; ReactDOM.render(<App isHappy={ true } />, document.getElementById('app')); 1 2 3 4 5 Maarten Mulders (@mthmulders)#reactworkshop
  22. 22. C JSX (2) ASML PHIA RDSA const Ticker = ({ symbol }) => <div>{ symbol }</div>; const TickerList = ({ symbols }) => symbols.map(   (symbol) => <Ticker symbol={ symbol } /> ); const symbols = ['ASML', 'PHIA', 'RDSA']; ReactDOM.render(<TickerList symbols={ symbols } />, document.getElementById('app')); 1 2 3 4 5 6 7 8 Maarten Mulders (@mthmulders)#reactworkshop
  23. 23. M Maarten Mulders (@mthmulders)#reactworkshop
  24. 24. A So far, we've declared components and elements. Babel or tsc transpiles JSX into React.createElement(...) invocations: <Greeter name={ 'world' } /** transpiles into React.createElement(Greeter, { name: 'world' }, null) Maarten Mulders (@mthmulders)#reactworkshop
  25. 25. A The React.createElement invocations form a tree of components. React maintains a virtual DOM based on your component tree. The virtual DOM is compared to the actual DOM. Only necessary changes are executed. Maarten Mulders (@mthmulders)#reactworkshop
  26. 26. R React syncs the virtual and the actual DOM based on two assumptions: 1. If two elements are of different type, the (sub) tree will be different. 2. The key prop identifies child elements over re-renders. Maarten Mulders (@mthmulders)#reactworkshop
  27. 27. 1 E Hej, Jfokus const SwedishGreeter = ({ name }) => <div>Hej, { name }</div> const DutchGreeter = ({ name }) => <div>Hallo, { name }</div>; const EnglishGreeter = ({ name }) => <div>Hello, { name }</div>; const App = ({ language, name }) => {  switch(language) {    case 'se': return <SwedishGreeter name={ name } />    case 'nl': return <DutchGreeter name={ name } />    case 'en':    default  : return <EnglishGreeter name={ name } />  } }; ReactDOM.render(<App name='Jfokus' language='se' />, document.getElementById('app')); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Maarten Mulders (@mthmulders)#reactworkshop
  28. 28. 2 T KEY ASML PHIA RDSA const Ticker = ({ symbol }) => <div>{ symbol }</div>; const TickerList = ({ symbols }) => symbols.map(   (symbol) => <Ticker key={ symbol } symbol={ symbol } /> ); const symbols = ['ASML', 'PHIA', 'RDSA']; ReactDOM.render(<TickerList symbols={ symbols } />, document.getElementById('app')); 1 2 3 4 5 6 7 8 9 Maarten Mulders (@mthmulders)#reactworkshop
  29. 29. L D T Start with a mockup of what you want to build Inbox @Work @Home @Supermarket Learn React Build my first React app Add new task Add Task Learn React Due date April 13, 2020 Completed yes List Inbox 1. Identify component hierarchy 2. Create skeleton of component hierarchy Use background or border colors to distinguish componentsMaarten Mulders (@mthmulders)#reactworkshop
  30. 30. A B 1. Event handling 2. Storing data 1. Temporarily (in your app) 2. Permanent (in your browser) 3. Getting data over HTTP Maarten Mulders (@mthmulders)#reactworkshop
  31. 31. R E Similar to DOM event handling, but 1. event names are different: onClick vs onclick. 2. event handles are always functions, never strings. 3. event handlers receive an synthetic event - browser-agnostic! Maarten Mulders (@mthmulders)#reactworkshop
  32. 32. B C C Clickme! const Greeter = ({ name }) => {     const callback = () => alert(name)     return <button onClick={ callback }>Click me!</button> } ReactDOM.render(<Greeter name='Jfokus' />, document.getElementById('app')); 1 2 3 4 5 6 Maarten Mulders (@mthmulders)#reactworkshop
  33. 33. K 1. Inside a component 2. Shared in your app Maarten Mulders (@mthmulders)#reactworkshop
  34. 34. L S C Counter: 0 +   ‑ const Counter = () => {    const [ counter, setCounter ] = React.useState(0); // Look, a Hook!    const increase = () => setCounter(counter + 1)    const decrease = () => setCounter(counter ­ 1)    return <div>Counter: { counter }<br />                <button onClick={ increase }>   +   </button> &nbsp;                <button onClick={ decrease }>   ­   </button>           </div> } ReactDOM.render(<Counter />, document.getElementById('app')); 1 2 3 4 5 6 7 8 9 10 11 12 Maarten Mulders (@mthmulders)#reactworkshop
  35. 35. U U I Greetme! const Greeter = () => {    const [ name, setName ] = React.useState('');    const updateName = (e) => setName(e.target.value);    const callback = () => window.alert('Hi ' + name + '!');    return <div><input type='text' onChange={ updateName } ></input><br />                <button onClick={ callback }>Greet me!</button></div> } ReactDOM.render(<Greeter />, document.getElementById('app')); 1 2 3 4 5 6 7 8 9 10 Maarten Mulders (@mthmulders)#reactworkshop
  36. 36. S S A Share state between components by passing props. But what if they have a few components in between?           Producer                    In Between 1                  In Between 2                    Consumer            “Seperation of concerns, anyone? Maarten Mulders (@mthmulders)#reactworkshop
  37. 37. C Welcome, Jfokus const UserContext = React.createContext(); const UserDisplay = () => {    const user = React.useContext(UserContext);    return <div>Welcome, { user ? user.name : 'guest' }</div>; }; const InBetween2 = () => <UserDisplay /> const InBetween1 = () => <InBetween2 /> const App = ({ name }) => {    const user = name ? { name } : undefined;    return (<UserContext.Provider value={ user }>                <InBetween1 />            </UserContext.Provider>); } ReactDOM.render(<App name='Jfokus' />, document.getElementById('app')); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Maarten Mulders (@mthmulders)#reactworkshop
  38. 38. U C Current theme: light. Toggle! const ThemeContext = React.createContext(); const ThemeDisplay = () => {    const context = React.useContext(ThemeContext);    return <div>Current theme: { context.theme }.</div> }; const ThemeToggle = () => {    const context = React.useContext(ThemeContext);    return <button onClick={ context.toggle }>Toggle!</button> }; const App = () => {    const [ theme, setTheme ] = React.useState('light');    const toggle = () => setTheme(theme === 'dark' ? 'light' : 'dark');    return <ThemeContext.Provider value={ { theme, toggle } } >               <ThemeDisplay /> / 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18   Maarten Mulders (@mthmulders)#reactworkshop
  39. 39. Alternatively, use .contextType for consuming a Context ⟶ Only works for classes! class WhateverDisplay extends React.Component { render() { return <div className={ this.context.theme }> div>; } } WhateverDisplay.contextType = ThemeContext; Maarten Mulders (@mthmulders)#reactworkshop
  40. 40. G 1. What state do we have? 2. Where does it live? Maarten Mulders (@mthmulders)#reactworkshop
  41. 41. S , anyone? limited storage (~ 4096 bytes each, max 50 per domain) can be insecure (sent to web server) Maarten Mulders (@mthmulders)#reactworkshop
  42. 42. L S S S Part of the Stores and retrieves string values Serialise objects with JSON.stringify() Deserialise with JSON.parse() Aren't sent to a web server Persistent during browser session with sessionStorage over browser shutdowns with localStorage Web Storage API Maarten Mulders (@mthmulders)#reactworkshop
  43. 43. U S S Counter: 0 + ‑ const initialValue = Number(sessionStorage.getItem('counter')) || 0; const App = () => {    const [ counter, setCounter ] = React.useState(initialValue);    const updateCounter = (value) => {        setCounter(Number(value));        sessionStorage.setItem('counter', value);    }    const increase = () => updateCounter(counter + 1);    const decrease = () => updateCounter(counter ­ 1);    return <div>Counter: { counter }<br />                <button onClick={ increase }>   +   </button>                <button onClick={ decrease }>   ­   </button>           </div> }; / 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18   Maarten Mulders (@mthmulders)#reactworkshop
  44. 44. F HTTP Prerequisites: 1. A JavaScript function to fetch some data 2. A component to show the fetched data Maarten Mulders (@mthmulders)#reactworkshop
  45. 45. 1 A API const checkStatus = (response) { if (response.status 200 response.status < 300) { return Promise.resolve(response); } else { return Promise.reject(`HTTP error ${response.status}: ${response.statusText}`); } }; const parseJson = (response) response.json(); const url = 'https: hqd7fvgovgs2jyoosjgryaylcy.apigateway.eu frankfurt-1.oci.customer oci.com' + '/v1/joke'; const getJoke = () { return fetch(url) .then(checkStatus) .then(parseJson) .then(response response.joke); }; Maarten Mulders (@mthmulders)#reactworkshop
  46. 46. 2 A My friend didn't understand cloning. That makes two of us. const RandomJoke = () => {    const [ { joke, loading }, setState ] = React.useState({ loading: true });    const fetchRandomJoke = async () => {        // Does the actual API call to Oracle Cloud function,        // see code on previous slide.        const joke = await getJoke();        setState({ loading: false, joke });    }    React.useEffect(() => {        fetchRandomJoke()    }, [ /* intentionally left empty */ ]);    if (loading) return <div>Loading...</div>    return <div>{ joke }</div>; }; ReactDOM.render(<RandomJoke />, document.getElementById('app')); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Maarten Mulders (@mthmulders)#reactworkshop
  47. 47. W If the API will be available at the same domain as the web app, use a proxy. Add to package.json (assuming you use )Create React App "proxy": "https: gtdapp.mulders.it" Maarten Mulders (@mthmulders)#reactworkshop
  48. 48. L D T Start with a mockup of what you want to build Inbox @Work @Home @Supermarket Learn React Build my first React app Add new task Add Task Learn React Due date April 13, 2020 Completed yes List Inbox 1. Identify component hierarchy 2. Create skeleton of component hierarchy Use background or border colors to distinguish componentsMaarten Mulders (@mthmulders)#reactworkshop
  49. 49. W GTD REST API 1. Register an account: 2. Install the client lib: 3. Update package.json: 4. Restart NPM: curl d 'username= &password= ' https: gtdapp.mulders.it/public/users/register npm i gtd lib "proxy": "https: gtdapp.mulders.it" Maarten Mulders (@mthmulders)#reactworkshop
  50. 50. V O S Maarten Mulders (@mthmulders)#reactworkshop
  51. 51. T For unit testing, Jest and Enzyme are very powerful solution. Install them with Create a file src/setupTests.js with npm i -D enzyme enzyme adapter react-16 react test renderer import { conf gure } from 'enzyme'; import Adapter from 'enzyme adapter react-16'; conf gure({ adapter: new Adapter() }); Maarten Mulders (@mthmulders)#reactworkshop
  52. 52. W Tests go in: Files with .js suffix in __tests__ folders. Files with .test.js suffix. Files with .spec.js suffix. Run them with npm test. Maarten Mulders (@mthmulders)#reactworkshop
  53. 53. T : S R ⚠ Does not render any child components import React from 'react'; import { shallow } from 'enzyme'; import Greeter from ' /Greeter'; describe('<Greeter ', () { it('renders a friendly greeting', () { const wrapper = shallow(<Greeter name='folks' ); expect(wrapper.text()).toBe('Hi folks!'); }); }); Maarten Mulders (@mthmulders)#reactworkshop
  54. 54. T E H describe('<MyButton ', () { it('handles click events', () { const onButtonClick = jest.mock(); const wrapper = shallow(<Foo onButtonClick={ onButtonClick } ); wrapper.f nd('button').simulate('click'); expect(onButtonClick).toBeCalled(); }); }); Maarten Mulders (@mthmulders)#reactworkshop
  55. 55. F DOM R ⚠ Needs an environment that "looks like" a browser, e.g. . Otherwise, add ­­env=node to the test script in package.json. import React from 'react'; import { mount } from 'enzyme'; import Greeter from ' /Greeter'; describe('<Greeter ', () { it('renders a friendly greeting', () { const wrapper = mount(<Greeter name='Folks' ); expect(wrapper.text()).toBe('Hi Folks!'); }); }); jsdom Maarten Mulders (@mthmulders)#reactworkshop
  56. 56. W - Start with a mockup of what you want to build Inbox @Work @Home @Supermarket Learn React Build my first React app Add new task Add Task Learn React Due date April 13, 2020 Completed yes List Inbox 1. Identify component hierarchy 2. Create skeleton of component hierarchy Use background or border colors to distinguish componentsMaarten Mulders (@mthmulders)#reactworkshop

×