Reactjs

From Training Material
Jump to navigation Jump to search


Reactjs

Reactjs Training Materials

Introduction

  • Developed by engineers at Facebook
    • "A JavaScript library for building user interfaces"
  • React enables websites to display
    • Complex animations
    • Large volumes of data
    • Other memory-heavy tasks without slowing down

Intro Con't

  • Declarative
  • Component-Based
  • Reusable and independent

Declarative

  • Declarative views make the code more predictable and easier to debug
  • Very easy way to create interactive UIs
  • Simple views for each state in the application
  • Efficient update and render of the right components when the data changes

Component-Based

  • Encapsulated components that manage their own state
    • Compose them to make complex UIs
  • Component logic is written in JavaScript instead of templates
    • Easy to pass rich data through the app
    • In the same time keeps state out of the DOM

Reusable

  • Independent from technology stack used in the whole project
  • We can develop new features without rewriting existing code
  • Can render on the server (for example using Nodejs)
  • Can power mobile apps using React Native

Design principles behind React

  • JSX
  • Rendering Elements
  • Components and props

JSX

Rendering Elements

Building your first component

  • Component lets split the UI into independent, reusable and isolated pieces
  • Components are like JavaScript functions (conceptually)
    • Accept arbitrary inputs (called "props")
      • Props are read-only (function can't change it's own props)
    • Return React elements describing what should appear on the screen
  • The simple one-page app example
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>
    <script crossorigin>
        // const process = { 'env': { 'NODE_ENV' : 'development' } };
    </script>
    <script crossorigin src="https://unpkg.com/react@18.3.1/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
  </head>
  <body>
    <div id="rooty"></div>
    <script type="text/babel">

      ReactDOM.createRoot(
        document.getElementById('rooty')
      ).render(<h1>Hi Universe!</h1>);

    </script>
  </body>
</html>

How components work in React

  • Components implement a render() method
    • Takes input data and returns what to display
    • Often uses an XML-like syntax called JSX
    • Can access input data passed into the component via this.props
    • Input data passed into the component can be accessed by render() via this.props

Example 1

        //// JSX code
        class HelloMessage extends React.Component {
            render() {
            // JSX element treated as JavaScript expression:
            // can be saved in a variable, passed to a function, stored in an object or array, etc
                return <div>Hello {this.props.name}</div>;
            }
        }

        ReactDOM.createRoot(document.getElementById('rooty')).render(<HelloMessage name="Robert" />);


        //// COMPILED JS
        // class HelloMessage extends React.Component {
        //     render() {
        //         return React.createElement(
        //         "div",
        //         null,
        //         "Hello ",
        //         this.props.name
        //         );
        //     }
        // }

        // ReactDOM.createRoot(document.getElementById('rooty')).render(React.createElement(HelloMessage, { name: "Robert" }));

Exercise 1

Rewrite it into React function (-:

The component life cycle

  • In application with many components
    • Components are destroyed
    • Resources taken by the components have to be free up
  • Mounting
    • Whenever the component is rendered to the DOM for the first time
  • Unmounting
    • Whenever the DOM produced by the component is removed
  • Special(our own) methods called lifecycle hooks
  • setState() schedules updates to the component local state
  • "Common lifecycles"

Handling state in React

  • State is similar to props
    • But it is private and fully controlled by the component
    • Local state is a feature available only to classes
  • Component
    • Takes input data (accessed via this.props)
    • Can maintain internal state data (accessed via this.state)
    • When a component's state data changes, the rendered markup will be updated by re-invoking render()

Example 2

//// JSX part
class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {secondsElapsed: 0};
  }

  tick() {
    this.setState((prevState) => ({
      secondsElapsed: prevState.secondsElapsed + 1
    }));
  }
  // Lifecycle hooks
  componentDidMount() {
    this.interval = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    return (
      <div>Seconds Elapsed: {this.state.secondsElapsed}</div>
    );
  }
}

//// 'createRoot()' replaced 'ReactDOM.render()', below previous way (for React 17 and older)
// ReactDOM.render(<Timer />, document.getElementById('rooty'));
ReactDOM.createRoot(document.getElementById('rooty')).render( <Timer /> );

//// COMPILED JS, rendering part only
// ( ... )
//   render() {
//     return React.createElement(
//       "div",
//       null,
//       "Seconds Elapsed: ",
//       this.state.secondsElapsed
//     );
//   }
// ( ... )

Exercise 2

Guess what? (-!

  • Write function'ish version of it - of course!

Managing state

  • React on its own does not provide built-in support for state management
  • The React community uses libraries
    • Redux
    • MobX
    • xstate
  • React state vs. Redux state

Redux

  • Relies on synchronizing data through a centralized and immutable store of data
  • Updates to that data will trigger a re-render of the application
  • State is updated in an immutable fashion
    • Sending explicit action messages which must be handled by functions called reducers
  • Because of the explicit nature, it is often easier to reason about how an action will affect the state of our program

MobX

  • Relies on functional reactive patterns
    • State is wrapped through observables and passed through as props
    • Keeps state fully synchronized for observers
      • Simply marks state as observable.
  • Already written in TypeScript

xstate

React state vs. Redux state

  • Use React state for things that don’t matter globally
    • The form is one-off
    • The form’s data isn’t needed outside of it
    • The form’s state is so complex, managing all of that with Redux would be even worse
  • Use Redux for state that does matter globally
    • We want the input value to outlive the component
    • We have to have several instances of the form, synced
    • We want to share particular input between different forms
    • We want certain form state to have the impact on the rest of our app

Integrating React with other frameworks and plugins

Example 3, with ext plugin

// <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/remarkable/1.7.1/remarkable.js"></script>
// 
// JSX code
class MarkdownEditor extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {value: 'Type some *markdown* here! # babe - meow'};
  }

  handleChange(e) {
    this.setState({value: e.target.value});
  }

  getRawMarkup() {
    var md = new Remarkable();
    return { __html: md.render(this.state.value) };
  }

  render() {
    return (
      <div className="MarkdownEditor">
        <h3>Input</h3>
        <textarea
          onChange={this.handleChange}
          defaultValue={this.state.value} />
        <h3>Output</h3>
        <div
          className="content"
          dangerouslySetInnerHTML={this.getRawMarkup()}
        />
      </div>
    );
  }
}

ReactDOM.createRoot(document.getElementById('rooty')).render(<MarkdownEditor />);

Exercise 3

  1. Yup, you know what to do now, for sure (-'
    • You do, right? (-,
    • Function, obviously!
  2. Oh well, let's "kill one stone with many birds", shall we?
    • Create short training course materials: "How to kill one stone with many birds?"
    • Keep it really simple as a presentation - just a couple of slides (2 or 3)
    • Use this extension - https://github.com/rexxars/react-markdown

Bringing it all together - an application

  • Using props and state usually is enough to create the whole application
  • Below TODO list example
    • uses state to track the current list of items
    • Also tracks the text that the user has entered
  • Event handlers appear to be rendered inline
    • But they will be collected and implemented using event delegation

Example 4, app example

// JSX code
class TodoApp extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.state = {items: [], text: ''};
  }

  render() {
    return (
      <div>
        <h3>TODO</h3>
        <TodoList items={this.state.items} />
        <form onSubmit={this.handleSubmit}>
          <input onChange={this.handleChange} value={this.state.text} />
          <button>{'Add #' + (this.state.items.length + 1)}</button>
        </form>
      </div>
    );
  }

  handleChange(e) {
    this.setState({text: e.target.value});
  }

  handleSubmit(e) {
    e.preventDefault();
    var newItem = {
      text: this.state.text,
      id: Date.now()
    };
    this.setState((prevState) => ({
      items: prevState.items.concat(newItem),
      text: ''
    }));
  }
}

class TodoList extends React.Component {
  render() {
    return (
      <ul>
        {this.props.items.map(item => (
          <li key={item.id}>{item.text}</li>
        ))}
      </ul>
    );
  }
}

ReactDOM.createRoot(document.getElementById('rooty')).render(<TodoApp />);

Exercise 4

Yeah, again - I know (---;

  • Make it hooked!

Setting up your development environment

  • Create new app
  • Add React to an existing app

Create new app

Create new app Con't

  • Later we can adjust it and move to production
    • change the configuration
    • provide security (handling users via login and passwd, etc)
    • setup the db (mysql, mongodb, etc)
    • wire our existing web services, write new

Add React to an Existing App

  • No need to rewrite your app to start using React.
  • Start with small part of application (small widget), and see if it works well for our use case
  • React can be used without a build pipeline
  • It's recommended to set it up to be more productive
  • Build pipeline
    • Package manager (Yarn, npm, etc)
      • Vast ecosystem of third-party packages, easy to install or update them
    • Bundler (webpack, Browserify, vite, parcel, rsbuild, etc).
      • Lets to write modular code and bundle it together into small packages to optimize load time
    • Compiler (Babel, etc)
      • Lets to write modern JavaScript code that still works in older browsers

Exercise 5, Full envi, ts way

We will create simple application with 'vite' and 'nodejs'.
We will do it in steps, to cover most important elements of 'Reactjs'.
Each step will be explained separately.

Envi preparation steps (command line, in linux you might gonna need also 'sudo ' before the 'npm')
 npm create vite@latest mya -- --template react-ts
 cd mya
 npm i
 npm run dev

How to use vite with nodejs goodies

# enabling app in dev envi
npm run dev

# builds the app for production to the `build` folder
npm run build
  1. Step 1
    • Looking at the template code
  2. Step 2
    • change the file src/App.tsx
      import './App.css';
      
      function App() {
        return (
          <div className="App">
            <p>Hi Universe!</p>
          </div>
        );
      }
      
      export default App;
      
  3. Step 3 (tricky one!)
    • Create new component here components/Text.tsx
      const Text = () => {
          return (
              <p className="text">Lorem ipsum</p>
          ); 
      }
      
      export default Text;
      
  4. Step 4
    • Modify main component src/App.tsx
      import './App.css';
      import Text from './components/Text';
      
      function App() {
        return (
          <div className="App">
            <p>Hi Universe!</p>
            <Text />
          </div>
        );
      }
      
      export default App;
      
  5. Step 5
    • Understanding state. Change main component file again src/App.tsx
      import './App.css';
      import { React, useState } from 'react';
      import Text from './components/Text';
      
      function App() {
        const [text, setText] = useState('Not clicked!');
      
        function onButtonClick() {
          setText('Clicked!');
        }
      
        return (
          <div className="App">
            <p>Hi Universe!</p>
            <Text />
            <p>{text}</p>
            <button onClick={onButtonClick}>Click</button>
          </div>
        );
      }
      
      export default App;
      
  6. Step 6 (couple of fix-me cases here!)
    • Passing parameters(also state) to components.
      • Step 6.1. Modify file src/components/Text.tsx
        import PropTypes from 'prop-types';
        
        const Text = (props) => {
            return (
                <div>
                    <p className="text">{props.staticText}</p>
                    <p className="text">
                        {`Text from parent: ${props.clickText}`}
                    </p>
                </div>
            ); 
        }
        
        Text.propTypes = {
            staticText: PropTypes.string.isRequired,
            clickText: PropTypes.string.isRequired
        }
        
        export default Text;
        
      • Step 6.2. Modify main component file src/App.tsx
        import './App.css';
        import { React, useState } from 'react';
        import Text from './components/Text';
        
        function App() {
          const [text, setText] = useState('Not clicked!');
        
          function onButtonClick() {
            setText('Clicked!');
          }
        
          return (
            <div className="App">
              <p>Hi Universe!</p>
              {/* <Text /> */}
              <Text
                // Comment out the line below and check the 'console'
                staticText="Text from child component" 
                clickText={text} 
              />
              <p>{text}</p>
              <button onClick={onButtonClick}>Click</button>
            </div>
          );
        }
        
        export default App;
        

Defining our components' parent/child relationships

Lifting state up

  • A single "source of truth" for any data that changes
    • The state is first added to the component that needs it for rendering
    • Then, if other components also need it, we can lift it up to their closest common ancestor
    • Don't try to sync the state between different components, rely on the top-down data flow
  • More "boilerplate" code than in two-way binding approaches
    • But it takes less work to find and isolate bugs
      • any state "lives" in some component and that component alone can change it
      • the surface area for bugs is greatly reduced
    • We can also implement any custom logic to reject or transform user input
  • If something can be derived from either props or state, it probably shouldn’t be in the state

Containment

  • To reuse code between components
    • Composition model is recommended instead of inheritance
  • For not known children AOT in generic components
    • pass children elements directly with {props.children}
      • by nesting the JSX
    • For multiple generic "barrels" in a component use our own convention
      • pass our own React elements as props like any other data

Specialization

  • Components as special cases of other components
    • PublicCourseEvent and ConsultancyEvent are special cases of CourseEvent
  • Use composition
    • more "specific" component renders a more “generic” one
    • and configures it with props
  • To reuse non-UI functionality between components
    • extract it into a separate JavaScript module
    • the components may import it and use its constructs without extending it

Event handling and conditional rendering

Container vs Presentational Components

"Remember, components don’t have to emit DOM. They only need to provide composition boundaries between UI concerns"
  Dan Abramov (Co-author of Redux and Create React App)

Presentational Components

Dan Abramov's presentational components:

  • Are concerned with how things look
  • May contain both presentational and container components** inside, and usually have some DOM markup and styles of their own
  • Often allow containment via this.props.children
  • Have no dependencies on the rest of the app, such as Flux actions or stores
  • Don’t specify how the data is loaded or mutated
  • Receive data and callbacks exclusively via props
  • Rarely have their own state (when they do, it’s UI state rather than data)
  • Are written as functional components unless they need state, lifecycle hooks, or performance optimizations
  • Examples: Page, Sidebar, Story, UserInfo, List

Container Components

Dan's container components:

  • Are concerned with how things work
  • May contain both presentational and container components inside
    • but usually don’t have any DOM markup of their own except for some wrapping divs,
    • and never have any styles
  • Provide the data and behavior to presentational or other container components
  • Call Flux actions and provide these as callbacks to the presentational components
  • Are often stateful, as they tend to serve as data sources
  • Are usually generated using higher order components
    • such as connect() from React Redux, createContainer() from Relay, or Container.create() from Flux Utils,
    • rather than written by hand
  • Examples: UserPage, FollowersSidebar, StoryContainer, FollowedUserList

What are the benefits

  • Better separation of concerns
    • We understand our app and our UI better by writing components this way
  • Better reusability
    • We can use the same presentational component with completely different state sources
    • and turn those into separate container components that can be further reused
  • Presentational components are essentially our app’s palette
    • We can put them on a single page and let the designer tweak all their variations without touching the app’s logic
    • We can run screenshot regression tests on that page
  • This forces us to extract layout components such as Sidebar, Page, ContextMenu and use this.props.children
    • instead of duplicating the same markup and layout in several container components

Designing our React app

  • Prepare dry dummy interface
  • Break the UI into a Component Hierarchy
  • Build a static version in React (just props, no state yet)
  • Identify complete and minimal representation of UI state
  • Identify where our state should Live
  • Add inverse data Flow

Identify the minimal representation of UI state

Criteria for each piece of data (yes = probably not state)

  • Passed in from a parent via props?
  • Remain unchanged over time?
  • Computable based on any other state or props in our component?

Identify where our state should Live

For each piece of state in our application

  • Identify every component that renders something based on that state
  • Find a common owner component
    • a single component above all the components that need the state in the hierarchy
  • Either the common owner or another component higher up in the hierarchy should own the state
  • If we can’t find a component where it makes sense to own the state
    • create a new component simply for holding the state
    • and add it somewhere in the hierarchy above the common owner component

Main Exercises

  1. Pesel app
    • Migrate from jQuery to React
      • do it with React functions (-----:
      • Separate validations into JS module
  2. Jewel app
    1. First migrate it from Angular to React - yes, functioooooooons ruuuleeeeezzzzzz (--;
      • follow the best practices - design first, then code it (check again this Approach)
    2. Improve it with form element
    3. Extend it with adding new jewel to model
      • Add custom validation - adding same jewel not allowed
    4. Make sure gamers can see the list of available jewels
    5. Wrap it into simple navigation - use react-router module
      • Home page - shows only description of the game
      • Play it - redirects to the game itself
      • Show jewels - view with all the gems
      • Add Jewel - new jewel form
      • Pesel - form from the previous exercise
      • Simple - our first full example (clicked or not clicked)
    6. Make a view with single jewel
      • Improve our jewel - add description field
    7. Allow to remove one jewel
      • Extend it - removal of all jewels
    8. Make one jewel editable

Handling Forms in React, classes way

Collapsed by default, old-school way here only

Using context instead of props

  • Passing props can become inconvenient if
    • we need to pass through many components
    • many components need the same info
  • Context makes some information available
    • to any component in the tree below the parent
    • no matter how deep it is
    • no need to explicitly passing through props
  • The context itself does not hold the information
    • it only represents the kind of information we can provide or read from components
  • Related docs:
  • Exercise
    • Try to re-design our Ftj form with context
      • What can you say?
      • What could be in the custom context there and what not (or shouldn't)?

Routing in React

  • Static Routing
    • configuration happens before our app renders
  • Dynamic Routing
    • routing that takes place as our app is rendering
  • Nested routes
  • Responsive routes
  • https://reactrouter.com/en/main
  • Router framework

npx create-react-router@latest my-react-router-app

Adding Router lib

npm install react-router-dom

Dynamic routing

  • Routers
  • Route Matching
  • Main Route Props
  • Navigation

Routers

  • A router component at the core
  • Creates a specialized history object
  • For web projects ('react-router-dom' lib)
    • <BrowserRouter> - a server that responds to requests
    • <HashRouter> - a static file server
  • For mobiles ('react-router-native' lib)
    • <NativeRouter>

Route Matching

  • Comparing a <Route>'s path prop to the current location’s pathname
  • When matches it will render its content, otherwise null
  • A <Route> with no path will always match
  • Route matching components
    • <Route>
      • include to render content based on the location
      • list a number of possible <Route>s next to each other
    • <Routes>
      • used to group <Route>s together

Main Route Props

  • element - should be used for an existing element/component
    • React.Component, functional component, just element
  • path - the url's part

Navigation

  • <Link> - component to create links
  • <NavLink> - a special type of <Link>
    • can style itself as "active" when its to prop matches the current location
  • <Navigate> - to force navigation

Router example

import { Routes, Route, Link } from "react-router-dom";

const Home = () => (
  <div>
    <h2>Home</h2>
    <p>Navigation example</p>
    {/* <YourHomeComponent /> */}
  </div>
);

const About = () => (
  <div>
    <h2>About</h2>
    <p>What are we doing here?</p>
  </div>
);

const MyApp = () => {
    return (
        <div>
          <nav>
            <li>
              <Link to={"/"}>Home</Link>
            </li>
            <li>
              <Link to={"/about"}>About</Link>
            </li>
          </nav>
          <hr />
          <Routes>
              <Route path="/" element={<Home />} />
              <Route path="/about" element={<About />} />
          </Routes>
        </div>
    );
}

export default MyApp;

Nested Routes

  • Router has no 'nesting' API
  • Route is just a component (like div, etc)

Nested routes example

import { Routes, Route, Link, Outlet } from "react-router-dom";
import Timer from "./Timer";

function Home() {
    return ( <div>HOME page</div> );
}

function Messages() {
    return ( <div><p>Message 1</p><p>Message 2</p></div> );
}

function Todos() {
    return (
        <>
            <div>
                <h4>Todo 1</h4>
                <p>Fix the car</p>
            </div>
            <div>
                <h4>Todo 2</h4>
                <p>Spend some time with wife</p>
            </div>        
        </>
    );
}

function Menu() {
    return (
      <div>
        <h2>Menu</h2>
        <nav>
            <li><Link to={"messages"}>Messages</Link></li>
            <li><Link to={"todos"}>Todos</Link></li>
        </nav>
        {/* This element will render either <Messages> when the URL is
            "/messages" or <Todos> at "/todos"
        */}
        <Outlet />
      </div>
    );
}
  
function Nested() {
    return (
        <div>
            <h1>Main Menu</h1>            
            <nav>
                <li><Link to={"/"}>Home</Link></li>
                <li><Link to={"/sub"}>Sub</Link></li>
            </nav>            
            <Routes>
                <Route path="/" element={<Home />} />
                <Route path="sub" element={<Menu />}>
                    <Route path="messages" element={<Messages />} />
                    <Route path="todos" element={<Todos />} />
                </Route>
            </Routes>
        </div>        
    );
}

export default Nested;
Router Exercises
  1. Replace todos component with our Todos from this Example
  2. Add another link on the parent level
  3. Create 2nd level sub-menu
    • It should start from Messages
    • Put one link there only - showing some Contact details


Managing state with Redux

  • State of our app is stored in an object tree inside a single store
  • To change the state tree we emit an action, an object describing what happened
  • To specify how the actions transform the state tree, we write reducers
  • Doesn't support many stores
    • instead of adding stores, we split the root reducer into smaller reducers
    • independently operating on the different parts of the state tree
  • https://redux.js.org/introduction

Examples and exercises

  1. reduxExamples_
    • crud, jwt, hooks
  2. redux-toolkit-crud - fix me, again (-;
  3. Rewrite our dynamic form example with Redux
  4. Rewrite our FTJ app with Redux

Managing state with Mobx

  • Mobx is not a container for the state (not like Redux)
  • To make objects trackable for MobX
    • Use the @observable decorator or observable(object or array) functions
  • To create functions that can automatically derive their value from the state
    • Use the @computed decorator
  • To automatically run functions that depend on some observable state
    • Use autorun
    • useful for logging, making network requests, etc
  • To make React components truly reactive
    • Use the @observer decorator from the mobx-react package
    • They will update automatically and efficiently (also in large complex applications with large amounts of data)
  • https://mobx.js.org/

Example

// Define your state and make it observable
import {observable} from 'mobx';

var appState = observable({
    timer: 0
});


// Create a view that responds to changes in the State
import {observer} from 'mobx-react';

@observer
class TimerView extends React.Component {
    render() {
        return (<button onClick={this.onReset.bind(this)}>
                Seconds passed: {this.props.appState.timer}
            </button>);
    }

    onReset () {
        this.props.appState.resetTimer();
    }
};

ReactDOM.render(<TimerView appState={appState} />, document.body);


// Modify the State
appState.resetTimer = action(function reset() {
    appState.timer = 0;
});

setInterval(action(function tick() {
    appState.timer += 1;
}), 1000);

Mobx Exercise

Hooks

  • Let use: props, state, context, refs, lifecycle
    • without writing a class
    • provide new way to combine them
  • Optional and backwards-compatible
    • Work side-by-side with existing code - can be adopted gradually
  • Functions that:
    • let "hook into" React state and lifecycle features from function components
    • don’t work inside classes

Hooks Con't

  • Allow to reuse stateful logic without changing component hierarchy
  • Let split one component into smaller functions based on what pieces are related
    • Examples: setting up a subscription or fetching data
  • Common: useState, useEffect, useContext, useRef
  • Custom hooks - reusing stateful behavior between different components
  • Rules about calls
    • only at the top level (not in: loops, conditions, nested f)
    • only from function components (not from regular js) or custom hooks
  • Examples

Hooks Examples

  • useState()
  • useMemo()
  • useId()
  • useCallback()
  • useEffect()
  • useRef()
  • useContext()

useState()

  • lets to add a state variable to our component which returns an array with two values
    • Current State
    • Set Function
  • we can pass on initial value as well like below:- 234 and 'Gulliver'
import { useState } from 'react';

function Invoice() {
  const [invNo, setInvNo] = useState(234);
  const [companyName, setCompanyName] = useState('Gulliver');
}

useMemo()

  • lets to cache the result of a calculation between re-renders
    • prevents the unnecessary renders in our React Application
import { useMemo } from 'react';

function InvoicesList({ invoices, tab }) {
  const visibleInvoices = useMemo(
   () => filterInvoices(invoices, tab),
   [invoices, tab]
  );
}

useId()

  • for generating unique IDs that can be passed to accessibility attributes
    • which let to specify that two tags are related to each other
    • where we can use useId() generated ids instead of hardcoding them
import { useId } from 'react';

function PasswordField() {
  const passwordClueId = useId();

  return (
   <>
    <input type="password" aria-describedby={passwordClueId} />
    <p id={passwordClueId}>
   </>
  )
}

useCallback()

  • lets to cache a function definition between re-renders
  • useCallback caches a 'function' and useMemo caches a 'value/result of a calculation'
import { useCallback } fom 'react';

export default function BookingPage({ bookingId, referrer, theme }) {
  const handleSubmit = useCallback((leadDetails) => {
   post('/booking/' + bookingId+ '/buy' {
    referrer,
    leadDetails,
    });
   }, [bookingId, referrer]);
(...)

useEffect()

  • lets to perform side-effects in the component
  • side effects basically is an action which connects the component to the outside world
(...)
useEffect(() => {
  const connection = createConnection(serverCourseEventUrl, courseEventRoomId);
  connection.connect();
  return () => {
   connection.disconnect();
  };
 }, [serverCourseEventUrl, courseEventRoomId]);
(...)

useRef()

  • lets to reference a value that's not needed for rendering
  • similar to useState, the difference is it doesn't cause a re-render when the value changes
import { useRef } from 'react';

function RefreshDadesktopSandbox() {
  const intervalRef = useRef(0);
  const inputRef = useRef(null);
(...)
}

useContext()

  • lets to read and subscribe to context from our component
  • just like a data store (Redux, Mobx, etc)
import { useContext } from 'react';
import { ThemeLeadContext} from './ThemeLeadContext.js';

function SkinForLead() {
  const theme = useContext(ThemeLeadContext);
(...)
  return (
    <section className="np-lead-section">
      <ThemeLeadContext value={leadType + 1}>
        {children}
      </ThemeLeadContext>
    </section>
  );
}

Custom Hook

We can define our own hooks to use state and other React features without writing a class

  • As a function, it takes input and returns output
  • name starts with use (useQuery, useMedia.., etc)
  • returns a normal, non-jsx data (not like in functional component)
  • can use other hooks such as useState, useReF.. and other custom hooks (-;
  • some libraries also provide hooks - useForm (React Hook Form), useMediaQuery (MUI), useQuery (React Query), etc

Custom Hook Con't

Benefits:

  • Completely separate logic from user interface
  • Reusable in many different components with the same processing logic
    • Therefore, the logic only needs to be fixed in one place if it changes
  • Share logic between components
  • Hide code with complex logic in a component, make the component easier to read

When to use:

  • piece of code (logic) is reused in many places
  • logic is too long and complicated
  • we write custom react library (-:
  • ... ? (your ideas, please!)
  • Example - let's look at useNavigate() in react-router lib
  • Example/Exercise - react-ts-api


React Query

  • Most state management libraries (incl Redux)
    • good for working with client state
    • not for server state
      • persists remotely in a location the client side cannot control
      • can become outdated - we need to make asynchronous APIs for fetching and updating
  • React Query - one of the best libraries for managing server state
    • It helps to fetch, cache, synchronize and update data without touching any global state

React Query Con't

Helps:

  • to remove complicated and misunderstood code and replace with several React Query logic
  • easier to maintain and build new features without worrying about wiring up new server state data sources
  • make our application feel faster and more responsive
  • save bandwidth and increase memory performance
  • Example/Exercise - reactq-axios-ts


React Hook Form

  • Less code, more performant
    • reduces the amount of code we need to write
    • removes unnecessary re-renders
  • Isolate re-renders
    • ability to isolate component re-renders -> better performance on our page or app
  • Subscriptions - better performance
    • ability to subscribe to individual input and form State update without re-rendering the entire form
  • Faster mounting (than Formik, ReduxForm, etc)
  • More here https://react-hook-form.com/
  • Example/Exercise - react-hook-form-ts


MUI

MUI System

  • Set of utilities (Flexbox, Shadows, Typography, etc)
    • for quickly applying styles to components from: BUI, MUI, JUI
    • or to any third-party components
  • Helps to build custom designs more efficiently
    • and to rapidly lay out custom designs
  • Set of flexible, generic wrapper components (Box, Container, Grid, Stack)
    • can be quickly customized using the sx prop
      • styles can be defined directly within the components themselves
      • simplifies bulky and redundant definitions of styled-components
      • ensures consistency in one-off styles too
  • CSS tricks - https://css-tricks.com/snippets/css/a-guide-to-flexbox/

BaseUI

  • Library of "unstyled" React components (standalone) and low-level hooks
  • Set of foundational "headless" components
    • can be built with using any styling solution
    • no need to override any default style engine or theme
  • "skeletal" version of Material UI

MaterialUI

MaterialUI Exercise

  1. Here choose the environment
  2. Next decide about the template (or not)
  3. Finally try to use this builder

JoyUI

React with Typescript

React Native

  • Creates native apps for Android, iOS
  • Written in JavaScript — rendered with native code
  • Seamless Cross-Platform
    • React components wrap existing native code
    • interact with native APIs via React’s declarative UI paradigm and JavaScript
  • Setup and Using
    • Expo Go - quick and easy, but restricted SDK libs
    • Native CLI - longer to prepare, but gives access to many external libs
  • Related docs, examples

React Native Con't

npx create-expo-app nativeExample
cd nativeExample
npx expo start

Later on

  • connect on the same Wifi with phone
  • install Expo Go app on phone
  • scan the QR

Full stack with React

npx create-next-app@latest ftjrn
cd ftjrn
npm run dev

Server side rendering and SEO

  • Next.js
    • Server-rendered by default
    • Automatic code splitting for faster page loads
    • Simple client-side routing (page based)
    • Webpack-based dev environment which supports Hot Module Replacement (HMR)
    • Able to implement with Express or any other Node.js HTTP server
    • Customizable with our own Babel and Webpack configurations
    • Out-of-the-box tools for setting HTML tags for SEO
    • https://nextjs.org/learn/
    • https://zeit.co/blog/next
  • react-seo npm package
  • react-examples
    • 14-Server-Rendering
    • quickfix: remove internal from package.json npm run ssr-... scripts

Why not angular?

Debugging

Upgrading, Refactoring

React's Lego

Testing your React web application

JestGeneric.jpg

Jest Intro

  • No config
    • Supports - Babel, TypeScript, Node, React, Angular, Vue, etc
  • "Snapshotting"
  • Isolated
  • Good API

Overview of Jest

  • Zippy, secure
    • tests have unique global state
    • reliably runs tests in parallel
    • runs previously failed tests first
    • re-organizes runs based on how long test files take

Overview Con't

  • Code coverage (--coverage)
    • No setup needed, collects from entire projects (incl untested files)
  • Simple mocking
    • custom resolver for imports, mocks any object outside of scope
    • rich Mock Functions API with readable syntax

Overview

  • Whacking exceptions
    • rich context for test-fail: toStrictEqual, toHaveProperty, toMatchSnapshoot, toThrowError, etc
  • Well-documented
    • maintained by Christopher Pojer from Facebook and contributors within the community
  • Requires little configuration
  • Extendable

Benefits of testing

Why and how

  • Interfaces depend on browsers, user interactions, and many other variables
    • implementing an effective testing strategy is difficult
  • Consistent results are often affected by false negatives due to different factors (i.e. network)
  • Frequent updates in UI: improve the experience, maximize conversions, new features
  • Tests are hard to write and maintain ==> developers are less prone to cover their applications
  • Tests make developers more confident ==> speed and quality
  • Well tested code and well written tests ==> it works and is ready to ship
    • Easier to refactor the code ==> functionalities do not change during the rewrite
  • Running tests using Node.js and the console ==> faster, more predictable

Benefits of testing Con't

  • Is new feature affecting other parts of the application
    • Tests avoid regressions ==> tell if the new code breaks the old tests
  • Greater confidence in writing new features ==> faster releases
  • Code base more solid ==> new bugs can be reproduced, fixed, and covered by tests
  • Testing components is easy - well organised and assigned responsibilities and boundaries
    • Well written components (pure, composable, reusable) ==> can be tested as simple functions
  • Main goals to test
    • given different sets of props, components output is always correct
    • covering all the various states that a component can have
      • clicking a button ==> tests to check all the related event handlers

Benefits of testing Con't - tdd, design

  • Tests can verify the component's behavior on edge cases
    • all the props are null, or there is an error
  • With React we can mount a tree of components and test the integration between them
  • Techniques - test-driven development (TDD)
    • Applying TDD ==> writing the tests first and then writing the code to pass the tests
    • Force to think more about the design before implementing ==> usually leads to higher quality

Setting up the Testing Environment

  • Examples
    • Folder "testing"
    • Tests from "react-training"
  • Enzyme - helps to test Components' output
    • manipulate, traverse, and in some ways simulate (like with jQuery)
  • Cypress - e2e framework

Installing and Configuring Jest

  • Initial setup
## Installing
npm install --save-dev jest

## Config
jest --init

## The rest depends on other tools: babel, webpack, typescript, etc
  • More here:
    • jestjs.io/docs/getting-started#additional-configuration

Running Watch Mode to Test File Changes

live-server --cors #manual tests with real browser
jest -o  #runs only with uncommited changes (git, mercurial)
jest --watch  #runs jest -o by default
jest --watchAll  #runs all tests

### Interactively - Watch Usage: Press w to show more.

## Watch Usage
# › Press f to run only failed tests.
# › Press o to only run tests related to changed files.
# › Press q to quit watch mode.
# › Press p to filter by a filename regex pattern.
# › Press t to filter by a test name regex pattern.
# › Press Enter to trigger a test run.

More here: jestjs.io/docs/cli

Running Browser Tests through Node

npm test  #via 'create-react-app' it uses by default the extension called 'react-scripts'

Testing a Sample JavaScript Application

TDD - Test Driven Development

  • Red-Green-Refactor cycle
  • Triangulation
    • The more specific tests get, the more general production code needs to get
    • Always implement the simplest thing that will possibly work
    • Hard-coding when it's possible and to get to the real implementation - add more tests
  • AAA rule: Arrange(Assemble), Act, Assert
  • Design principles
    • DRY - Don't Repeat Yourself
      • Drying up tests when refactoring
    • YAGNI - You Ain't Gonna Need It
      • Hold off adding anything to project until we're really sure that it's necessary (adding a user story, a customer asks for it, etc)
      • For example create-react-app application template - favicon.ico, a sample logo, CSS files, etc

TDD Con't

TddJestReact.png

Good vs Great

Good test Great test
Arrange: Sets up test dependencies Short
Act: Executes production code under test Descriptive
Assert: Checks expectations are met Independent of other tests
lol Has no side-effects

Examples

  • Example 1 - "1oneDetailOnly"
  • Example 2 - "2viewsListAndDetail"

Design upfront

JewelsListViewDesign.png

Exercises

  1. ("ex1") Display in the UI the rest of fields from model
    • Wrap data into HTML table
    • Add a heading to Appointment to make it clear which appointment time is being viewed
    • Prepare fake data generator (DRY)
  2. Prepare new Find The Jewel project (name it ftj)
    • Use create-react-app ( cd ; cd Documents/reactjsMaterials ; npx create-react-app ftj )
    • Make oneJewel component and test it
    • Make listJewels component and test it
      • Clicked jewel button should be different then the rest of jewel buttons (add css class dynamically)

Testing a React App

  • Simple form and user input
  • Testing React Components
  • About Stateful Components

Set up, execute function, assert results

Example

  • "4simpleForm"

Exercises

  1. Add dropdown - choosing stylist (before time slot), filtering based on required service
    • reflect stylists availability and the choice (update the table)
  2. Make form for adding new jewel and test it
    • Refactor the app into JewelGame class component with state

Testing the Business Logic

JestJoke.jpeg

Test Doubles

  • Used to verify interactions with collaborating objects
  • Spies and stubs
  • Extracting helper code into modules (readability - shorter and clearer)

Examples

  • "6testDoubles"

Exercises

  1. Extend 6testDoubles
    • Add a test to CustomerForm - the error state is cleared when the form is submitted again
    • Update the AppointmentForm tests to use jest.fn(), jest.spyOn(), and all of the helpers
    • Extend AppointmentForm so that it submits an appointment using a POST request to /appointments (endpoint returns a 201 Created status without any body)
    • Update the tests in AppointmentsDayView to use the helpers
  2. Add engine component in ftj app
    • Test it with doubles
  3. In ftj app refactor 'adding new jewel' into another component

Testing the User Interface

  • Loader and render, shallow rendering
  • Forms
  • Filtering and Searching Data
  • Testing Router
  • Testing Redux
  • Testing GraphQL

Loader and render, shallow rendering

  • Stubbing out components
    • Loader components correctly instantiate rendering components.
  • Shallow rendering
  • Stubbing and spying on child components - avoids running their side effects (fetch requests, etc)
    • Easily assert that we set their props correctly
  • Examples - "8forms"

Forms

  • Client-side validation
  • Handling server errors
  • Indicating submit
  • Examples - "8forms"
  • Exercises
  1. Within "8forms"
    • Clear any validation errors when corrected
    • Use the 'onChange' handler instead of 'onBlur' (faster interaction with user)
    • Disables the Submit button after submitting
    • Write tests all functions within the formValidation module
    • Simplify 'handleSubmit' - extract doSave func (pulls out the main body of the if statement)
  2. With ftj
    • Validate adding new jewel, not allow when it exists already

Filtering and Searching Data

  • More complex user interactions (between UI and an API)
  • Order of adding features
  • Tests help admit when we're doing the wrong thing
  • Examples - "10searchingPaging"
  • Exercises
  1. With "10searchingPaging"
    • Disable the 'Previous' button if the user is on the first page
    • Disable the 'Next' button if the current listing has fewer than 10 records on display
    • The /customers endpoint supports a limit parameter - specifies the number of records that are returned
      • Provide a mechanism for the user to change the number of records returned on each page
  2. For ftj
    • Allow to search for jewels

Testing Router

  • General rules for testing React Router
  • Building a root component
  • Using the location query string to store component state
  • Examples - "12router"
  • Exercises
  1. For ftj
    • Make router for showing list of jewels and a single jewel

Testing Redux

  • Testing a Redux saga
  • Asynchronous requests with saga
  • Switching out component state for Redux state
  • Shifting workflow to Redux
  • Examples - "13redux"
  • Exercises
  1. For todo_ts
    • Add button "RemoveAll"

Testing GraphQL

  • Testing the Relay environment
  • Building the GraphQL reducer
  • Examples - "14graphql"
  • Exercises
  1. With "14graphql"
    • Reshape the remaining fetch calls to use their GraphQL counterparts

Running Snapshot Tests

JestSnapshot.png

Snapshot Tests

  • Useful especially when testing presentational components
    • They do not manage state
    • Typically used to display data passed down from parent components as props
    • or to display hardcoded data directly in the component itself
  • Provided by Jest
    • We simply want to make sure the HTML output of a component does not change unexpectedly
  • Case scenario - developer does change the component's HTML structure
    • He adds another paragraph element with static text
    • Snapshot test will fail and provide a visual of the changes
  • Example - "rtlExamples", 2
  • Exercise - in ftj make a snapshot test
    • Separate game description into new presentational component

Troubleshooting

  • jest-dom methods
    • allow to write more descriptive test code
    • provide better context-specific error messages
  • Using RTL (React Testing Library)
    • Approach
      • render React elements into the Document Object Model (DOM)
      • select resulting DOM elements
      • make assertions on the expected resulting behavior
    • Examples - "rtlExamples"

RTL examples

  • 1 - test-utils VS enzyme VS rtl
  • 2 - presentational, debug
  • 3 - user events, interacting with APIs, again TDD
  • 4 - integration testing, 3rd party plugins
  • 5 - updating dependencies, enzyme2rtl, test-utils2rtl, best practices
  • 6 - tools and plugins, more best practices
  • 7 - e2e, cypress, cucumber

Photos Sources

  • kurierhistoryczny.pl/uploads/articles/237/stanczykmaly_rf89RS.jpg
  • cdn.shopify.com/s/files/1/0882/5118/products/Batman-The-Killing-Joke-Deluxe-Graphic-Novel-1008696_1024x1024.jpeg?v=1461690370
  • wpblog.semaphoreci.com/wp-content/uploads/2019/01/Snapshot_Testing_React_Components_with_Jest_-_Semaphore_CI-1024x575.png