Upgrade to Pro — share decks privately, control downloads, hide ads and more …

React in 50 minutes (DubJUG)

React in 50 minutes (DubJUG)

You’ve heard about React, the JavaScript library for building web applications? And you’re wondering how to use it beyond the “Hello, World” stage? Then this talk is for you! Join me in an action-packed session full of live code examples where we’ll discover how you can use React to build the hottest web applications while keeping your head cool.

When you leave the room, you’ll know enough to build real-world web applications!

Maarten Mulders

March 01, 2023
Tweet

More Decks by Maarten Mulders

Other Decks in Programming

Transcript

  1. REACT IN 50 MINUTES
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  2. ABOUT ME






    @mthmulders
    @Java_Champions
    @OracleACE
    @InfoSupportBV
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  3. REACT...

    React is a library for declaratively building user
    interfaces using JavaScript and (optionally)
    XML.
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  4. REACT VS. OTHERS
    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
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  5. MODERN JAVASCRIPT
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  6. CLASSES
    class Amount {
    constructor(currency, value) {
    this.currency = currency;
    this.value = value;
    }
    getCurrency() {
    return this.currency;
    }
    }
    const text = new Amount('EUR', 15).getCurrency();
    document.getElementById('app').innerText = text;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    EUR
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  7. FUNCTIONS
    function isEven(number) {
    return number % 2 == 0;
    }
    const text = isEven(42)
    document.getElementById('app').innerText = text;
    1
    2
    3
    4
    5
    6
    true
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  8. ARROW FUNCTIONS
    const isEven = (number) => {
    return number % 2 == 0;
    }
    const text = isEven(42)
    document.getElementById('app').innerText = text;
    1
    2
    3
    4
    5
    6
    true
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  9. OBJECT DECOMPOSITION
    const person = { name : 'Jane Doe', age: 42, occupancy: 'JavaScript dev' };
    const { name, age } = person;
    const text = age
    document.getElementById('app').innerText = text;
    1
    2
    3
    4
    5
    42
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  10. ARRAY DECOMPOSITION
    const numbers = [ 'one', 'two', 'three' ];
    const [ first, second ] = numbers;
    const text = second
    document.getElementById('app').innerText = text;
    1
    2
    3
    4
    5
    two
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  11. OBJECT SHORTHAND NOTATION
    const name = 'Jane Doe';
    const age = 42;
    const person = { name, age };
    const text = JSON.stringify(person)
    document.getElementById('app').innerText = text;
    1
    2
    3
    4
    5
    6
    {"name":"Jane Doe","age":42}
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  12. STRING INTERPOLATION
    class Amount {
    constructor(currency, value) {
    this.currency = currency;
    this.value = value;
    }
    toString() {
    return `${this.currency} - ${this.value}`;
    }
    }
    const text = new Amount('EUR', 150).toString();
    document.getElementById('app').innerText = text;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    EUR - 150
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  13. BASIC JSX
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  14. WHAT IS JSX?
    A syntax extension to JavaScript
    real XML, not a string of characters
    allows embedded expressions
    supports attributes
    Can be nested
    Automatic XSS prevention
    But it has its limitations
    Needs to be transpiled to JavaScript
    e.g. React.createElement(...)
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  15. ELEMENTS
    Elements can be regular DOM elements... (for now, but not for long)
    const element = Hello, world
    ReactDOM.render(element, document.getElementById('app'));
    1
    2
    Hello, world
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  16. ATTRIBUTES
    Elements can have attributes, but they can have different names
    than HTML attributes:
    const element = I'm blue
    ReactDOM.render(element, document.getElementById('app'));
    1
    2
    I'm blue
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  17. ... and they can behave differently:
    const style = { color: 'red', fontWeight: 'bold' };
    const element = I'm blue
    ReactDOM.render(element, document.getElementById('app'));
    1
    2
    3
    I'm blue
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  18. SINGLE ROOT NODE
    Values must have a single root node (or an array)
    const element = [x,y]
    ReactDOM.render(element, document.getElementById('app'));
    1
    2
    3
    x
    y
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  19. COMPONENTS
    Function that returns a React element.
    const Greeter = (props) => Hello, world!
    ReactDOM.render(, document.getElementById('app'));
    1
    2
    Hello, world!
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  20. ADVANCED JSX
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  21. EXPRESSIONS IN JSX
    const answerToQuestionOfLife = 40 + 2;
    const askQuestionOfLife = () => answerToQuestionOfLife;
    const Example = () =>
    The answer to the ultimate question of life,
    universe and everything: { askQuestionOfLife() }
    ;
    ReactDOM.render(, document.getElementById('app'));
    1
    2
    3
    4
    5
    6
    7
    8
    The answer to the ultimate question of life, universe and
    everything: 42
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  22. OR USE YOUR PROPS / ARGUMENTS!
    const Greeter = (props) => Hello { props.name }!
    ReactDOM.render(, document.getElementById('app'));
    1
    2
    Hello Dublin!
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  23. OR USE YOUR PROPS / ARGUMENTS!
    Alternatively, using object decomposition:
    const Greeter = ({ name }) => Hello { name }!
    ReactDOM.render(, document.getElementById('app'));
    1
    2
    Hello Dublin!
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  24. CONTROL STATEMENTS INSIDE JSX
    const ClapHands = () => Clapping hands...;
    const DryTears = () => Drying tears...;
    const ShowEmotion = ({ happy }) => happy ? : ;
    ReactDOM.render(,
    document.getElementById('app'));
    1
    2
    3
    4
    5
    6
    7
    Clapping hands...
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  25. CONTROL STATEMENTS INSIDE JSX (2)
    const Ticker = ({ symbol }) => { symbol };
    const TickerList = ({ symbols }) => symbols.map(
    (symbol) =>
    );
    const symbols = ['HEIA', 'PHIA'];
    ReactDOM.render(,
    document.getElementById('app'));
    1
    2
    3
    4
    5
    6
    7
    8
    9
    HEIA
    PHIA
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  26. REACT "MAGIC"
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  27. AT BUILD TIME
    So far, we've written components and wired them together.
    Babel or tsc transpiles them to
    React.createElement(...) invocations:




    /** transpiles into */



    React.createElement(Greeter, { name: 'World' }, null)

    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  28. AT RUN TIME
    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.
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  29. RECONCILIATION
    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.
    This
    tells React what makes two elements "the same".
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  30. 1. ELEMENTS OF DIFFERENT TYPE
    const DutchGreeter = ({ name }) =>
    🇳🇱 Hallo, { name }!;
    const EnglishGreeter = ({ name }) =>
    🇬🇧 Hello, { name }!;
    const IrishGreeter = ({ name }) =>
    🇮🇪 Dhuit, { name }!;
    const App = ({ lang, name }) => {
    switch(lang) {
    case 'ie': return
    case 'nl': return
    case 'en':
    default : return
    }
    };
    ReactDOM.render(,
    document.getElementById('app'));
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    🇳🇱
    Hallo, Dublin!
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  31. 2. THE key PROP
    const randomPrice = () => 100 + Math.floor(Math.random() * 900)
    const Ticker = ({ symbol }) => { symbol }: { randomPrice() } — ;
    const symbols = ['HEIA', 'PHIA', 'ASML', 'KLMR'].map(
    (symbol) =>
    );
    ReactDOM.render(,
    document.getElementById('app'));
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  32. YOUR ENVIRONMENT
    1. Keeping state
    2. Reacting to events
    3. Fetching data over HTTP
    4. Storing data
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  33. LOCAL STATE INSIDE A COMPONENT
    const Counter = () => {
    const [ counter, setCounter ] = React.useState(0);
    return Counter: { counter }
    }
    ReactDOM.render(, document.getElementById('app'));
    1
    2
    3
    4
    5
    6
    7
    Counter: 0
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  34. REACTING TO EVENTS
    Similar to DOM event handling, but
    1. event names are different: onClick vs onclick.
    2. event handlers are always functions, never strings.
    3. event handlers are bound to a component, should not live
    globally.
    4. event handlers receive an synthetic event - browser-agnostic!
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  35. CLICK CALLBACKS
    const Counter = () => {
    const [ counter, setCounter ] = React.useState(0);
    const increase = () => setCounter(counter + 1);
    const decrease = () => setCounter(counter - 1);
    return Counter: { counter }

    +  
    -

    }
    ReactDOM.render(, document.getElementById('app'));
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Counter: 0

    + -
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  36. CHANGE CALLBACKS
    const Greeter = () => {
    const [ name, setName ] = React.useState('');
    const updateName = (e) => setName(e.target.value);
    const callback = () => alert(`Hi ${name}`);
    return

    Greet { name }!
    }
    ReactDOM.render(, document.getElementById('app'));
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10


    Greet !
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  37. FETCHING DATA OVER HTTP
    What we need:
    1. A bit of Plain Old JavaScript to fetch some data
    2. A component to show the fetched data
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  38. 1. A DATA RETRIEVAL API




















    const url = 'https://opendata.rdw.nl/resource/m9d7-ebf2.json';

    const getCar = (licenseNumber) => {

    return fetch(url + '?kenteken=' + licenseNumber)







    };

    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  39. 1. A DATA RETRIEVAL 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 url = 'https://opendata.rdw.nl/resource/m9d7-ebf2.json';

    const getCar = (licenseNumber) => {

    return fetch(url + '?kenteken=' + licenseNumber)

    .then(checkStatus)





    };

    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  40. 1. A DATA RETRIEVAL 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://opendata.rdw.nl/resource/m9d7-ebf2.json';

    const getCar = (licenseNumber) => {

    return fetch(url + '?kenteken=' + licenseNumber)

    .then(checkStatus)

    .then(parseJson)



    };

    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  41. 1. A DATA RETRIEVAL 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://opendata.rdw.nl/resource/m9d7-ebf2.json';

    const getCar = (licenseNumber) => {

    return fetch(url + '?kenteken=' + licenseNumber)

    .then(checkStatus)

    .then(parseJson)

    .then(response => `${response[0].merk} ${response[0].handelsbenaming}`);

    };

    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  42. 2. A COMPONENT TO SHOW THE FETCHED DATA
    const ShowCar = () => {
    const [ { car, loading }, setState ] = React.useState({ loading: true });
    const fetchCarDetails = async (licenseNumber) => {
    const car = await getCar(licenseNumber);
    setState({loading: false, car});
    }
    React.useEffect(() => {
    fetchCarDetails('33JFX4');
    }, [ ]);
    return loading ? Loading... : { car };
    };
    ReactDOM.render(, document.getElementById('app'));
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    OPEL ZAFIRA
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  43. STORING DATA IN YOUR BROWSER
    Local Storage & Session Storage
    Part of the
    Stores and retrieves string values
    Serialise objects with JSON.stringify()
    Deserialise with JSON.parse()
    Persistent
    during browser session with sessionStorage
    over browser shutdowns with localStorage
    Web Storage API
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  44. DELIVERING APPS
    1. Debugging
    2. Testing
    3. Building
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  45. DEBUGGING
    Install the React Developer Tools for your browser of choice.
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  46. INSPECTING COMPONENT TREE
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  47. DEBUGGING
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  48. TESTING YOUR COMPONENTS
    Use Jest (test platform & library) and (React) Testing Library
    (testing utilities)
    Render a React component in a unit test
    Make assertions about its output and behaviour
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  49. TESTING A SIMPLE COMPONENT
    import { render, screen } from '@testing-library/react'



    describe('', () => {

    it('should render text', () => {

    render();

    expect(screen.getByText(/hello, Dublin/i)).toBeVisible();

    });

    });

    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  50. TESTING BEHAVIOUR OF A COMPONENT
    import { fireEvent, render, screen } from '@testing-library/react'



    describe('', () => {

    it('should invoke action on click', () => {

    const callback = jest.mock();

    render();

    fireEvent.click(screen.getByRole('link'));

    expect(callback).toHaveBeenCalled();

    });

    });

    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  51. DEVELOPING & SHIPPING AN APP
    tl;dr: use (CRA)
    Uses Webpack, Babel, ESLint and a dozen of other tools
    Tested to work together
    Live-reloading of changed code
    Source maps for easy debugging
    Have an ready-to-go app in one command
    Create React App
    npx create-react-app my-next-killer-app



    // or



    npm i -g create-react-app

    create-react-app my-next-killer-app

    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  52. USING CRA
    npm run start to start developing
    npm run build to create a production build
    npm run test to run unit tests
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  53. TAKE AWAYS
    Use Create React App
    Think in (small) components
    Think declaratively
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide

  54. THANK YOU!
    REFERENCES & MORE INFORMATION



    Create React App
    Philippe De Ryck on "Building Secure React
    Applications"
    @mthmulders
    #reactin50mins Maarten Mulders (@mthmulders)

    View Slide