Categories
React

React – The Complete Guide – Udemy

Section 1: Getting Started

  • React is a JavaScript library for building user interfaces
    • A client-side JavaScript library
    • All about building modern, reactive user interfaces for the web
    • Declarative, component focused approach
  • React.js Alternatives

Section 2: JavaScript Refresher

  • declare variable
    • let -> variable values
    • const -> constant values
  • Arrow functions
    • keep it context (this issue)
    • parentheses can be emitted when exactly only one parameter
    • curly braces and return can be emitted when only return a value
const myFuc = () => {}
  • Exports & Imports (Modules)
    • default
    • named
  • Classes
    • Collection of properties and methods
    • Instantiation with new keyword
    • Inheritance with extends keyword
      • super() inside constructor function in ES6
  • Spread & Rest Operators
    • Spread – To split up array elements or object properties
    • Rest – To merge a list of function arguments into an array
// Spread
const newArray = [...oldArray, 1, 2];
const newObject = {...oldObject, newProp: 5 };

// Rest
function sortArgs(...args) {
  return args.sort();  
}
  • Destructuring
    • Extract array elements or object properties and store them in variables
// Array
[a, b] = ["Hello", "world"];
// Result: a = "Hello", b = "world"  


// Object
{ name } = { name: "Yujin", age: 29 }
// Result: name = "Yujin", age -> undefined
  • Data type
    • Primitive types – number, string & boolean
    • Reference types – object & array

Section 3: React Basics & Working with Components

  • Component – usable building block in user interface consisting of HTML & JavaScript
    • Reusability
    • Separation of Concerns
  • Declarative approach – define the desired target state(s) and let React figure out the actual JavaScript DOM instructions
  • JSX – JavaScript XML
    • Developer-friendly, and will be transformed to browser-friendly before serve to browser
    • Allow inserting JavaScript inside HTML – { JS code }
  • A component in React is just a JavaScript function
    • Customised components start with uppercase character while built-in HTML elements start with lower case
    • Only one root element per JSX snippet
      • wrap into one <div>
      • fragment
  • Passing Data within components via “Props” (properties)
    • Make components configurable from outside
    • Pass in as “attributes”
    • Receive all the attributes as “properties”, parameter to function, an object consists of key/value pairs
  • Self-closing tag when there is no content between the opening and closing tags
  • Reusable wrapper component – Card, Container…
    • children prop – the content between the opening and closing tag of the customised component
    • default HTML tags support className out of box but customised components not
return (
    <div>
      <h2>Let's get started!</h2>
      <Expenses items={expenses}></Expenses>
    </div>
);

// under the hood
return React.createElement(
  'div',
  {},
  React.createElement('h2', {}, "Let's get started!"),
  React.createElement(Expense, { items: expenses})
)
  • File organisation
    • Group components according to their functions
  • Arrow function
function App() {}
// equals
const App= () => {}

Section 4: React State & Working with Events

  • By default, components will be only evaluated once. They are functions, will be called when the page loaded.
  • State comes to aid
    • useState from ‘react’ library
      • Returns an Array with two items
        • Current state value
        • Function for updating the state value
          • Not only update the value, not right away but schedule the state update
          • Also re-evaluate the current component, if changes detected, re-render the changes
    • To define values as state where changes to these values would be reflected in the component
    • React Hook
      • useState is one of the most important hooks
      • Hooks must be called directly inside React component functions
  • Each component instance has its own set of state
  • Listen to User Input
    • onChange()
      • triggered on each stroke
      • event.target.value to get the value of the input field
  • Alternative: Use one state object to store multiple states
  //   const [enteredTitle, setEnteredTitle] = useState("");
  //   const [enteredAmount, setEnteredAmount] = useState("");
  //   const [enteredDate, setEnteredDate] = useState("");
  
const [userInput, setUserInput] = useState({
    enteredTitle: "",
    enteredAmount: "",
    enteredDate: "",
  });

  const titleChangeHandler = (event) => {
 // setEnteredTitle(event.target.value);
    setUserInput({
      ...userInput,
      enteredTitle: event.target.value,
    });
  };
  • When updating state depending on previous state
    setUserInput((prevState) => {
      return {
        ...prevState,
        enteredTitle: event.target.value,
      };
    });
  • Two-Way Binding
    • Reset after submit form
    • Add value attribute to input tag
  • Child-to-Parent Component Communication (Lifting State Up)
    • Pass function as props
    • Call function in the child component
  • Controlled & Uncontrolled Components
    • Controlled/Stateful – deals with logic, store states
    • Uncontrolled/Stateless – only responsible for presentation

Section 5: Rendering Lists & Conditional Content

  • {Array.map(item => ()) }
  • “keys” property of list
    • performance issue
    • state management
    • Let React aware of specific list item binding to the list component instance
  • Conditional Rendering

      {filteredExpenseItems.length === 0 ? (
        <p>No expenses found.</p>
      ) : (
        filteredExpenseItems.map((item) => (
          <ExpenseItem
            key={item.id}
            title={item.title}
            amount={item.amount}
            date={item.date}
          />
        ))
      )}

// OR

      {filteredExpenseItems.length === 0 && <p>No expenses found.</p>}
      {filteredExpenseItems.length > 0 &&
        filteredExpenseItems.map((item) => (
          <ExpenseItem
            key={item.id}
            title={item.title}
            amount={item.amount}
            date={item.date}
          />
        ))}

// OR add a new variable 
  • Dynamic Styles
    • value of style attribute needs double curly braces
      • one for JS variable
      • one for JS object
    • target CSS property
      • backgroundColor or “background-color”

Section 6: Styling React Components

  • Dynamic classes
className={`form-control ${isValid ? null : "invalid"}`}
  • Styled Components
    • A package helps binding style to component by generating a unique class for the component
    • tact template
const Button = styled.button`
  font: inherit;
  padding: 0.5rem 1.5rem;
  border: 1px solid #8b005d;
  color: white;
  background: #8b005d;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.26);
  cursor: pointer;

  &:focus {
    outline: none;
  }

  &:hover,
  &:active {
    background: #ac0e77;
    border-color: #ac0e77;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.26);
  }
`;
<FormControl className={!isValid && "invalid"} /> 

// OR 

<FormControl invalid={!isValid} /> // pass in as props
  • CSS Modules
    • Migration steps
      • Add .module to .css file name – Button.css -> Button.module.css
      • import styles from “./Button.module.css”
      • className={styles.button}
    • Under the hood: create a unique class name

Section 7: Debugging React Apps

  • Warning from IDE
  • Browser console -> Breakpoints -> Step by step
  • React DevTools -> Components Tab

Section 9: Fragments, Portals & “Refs”

  • JSX Limitations
    • Can’t return more than one “root” JSX element – one function can only return one value
      • Wrap multiple elements in one <div></div> – could end up in “<div> soup”, unnecessary <div>s
      • Put multiple elements as an array – need to add key
      • A Wrapper Component
      • Default React Fragment – empty wrapper component
// Wrapper Component
const Wrapper = (props) => {
  return props.children;
};

export default Wrapper;

// Fragment
<React.Fragment></React.Fragment>
// OR
<></>
  • React Portals
    • Overlays and any related components nested deep in components is not ideal from semantical and a “clean HTML structure” perspective
    • Move the component to an actual DOM element
// index.html, add next to the #root element    
<div id="backdrop-toot"></div>
<div id="overlay-root"></div>

// Modal.js component
ReactDOM.createPortal(
        <ModalOverlay
          title={props.title}
          message={props.message}
          onConfirm={props.onConfirm}
        />,
        document.getElementById("overlay-root")
      )
  • Refs
    • Need only to read the value instead of modifying the value
    • Steps to implement
      • Initial a ref with useRef()
      • Connect the returned value to the HTML node with
        ref ={returned_value}
      • It has a current property which holds the actual HTML DOM node the ref is connected with
  • Controlled vs Uncontrolled Components
    • Controlled components
      • Connected with State, whose value is controlled by React
    • Uncontrolled components
      • Connected with Ref, value controlled by DOM element

Section 10: Effects, Reducers & Context API (!!!)

  • “Effect” / “Side Effect”
    • Main job of React – Render UI & React to User Input
      • Evaluate & Render JSX
      • Manage State & Props
      • React to Events & Input
      • Re-evaluate Component up State & Props Changes
    • Side Effect – must happen outside of the normal component evaluation and render cycle
      • Store Data in Browser Storage
      • Send Http Requests to Backend Servers
      • Set & Manage Timers
    • useEffect()
      • When dependencies is an empty array, would run only on first evaluation
      • Can be applied to actions that are executed in response to some other actions
      • Cleanup function in useEffect() – Run before each side effect function except for the first time
// No dependency -runs every time after a state update / component rendering including first rendering
useEffect(() => {
    const isLoggedIn = localStorage.getItem("isLoggedIn");
    if (isLoggedIn === "1") setIsLoggedIn(true);
 });
  

// An empty array as dependency -runs on first component rendering
useEffect(() => {
    const isLoggedIn = localStorage.getItem("isLoggedIn");
    if (isLoggedIn === "1") setIsLoggedIn(true);
}, []);

// Cleanup function
useEffect(() => {
    const isLoggedIn = localStorage.getItem("isLoggedIn");
    if (isLoggedIn === "1") setIsLoggedIn(true);

  return () => {};
}, [enteredPassword]);
  • userReducer() for State Management
    • Multiple states, multiple ways of changing it or dependencies to other states
  • Context API
    • Avoid redundant function passing for state sharing – prop chain
    • Component-wide, “behind-the-scences” State Storage
    • Steps to implement:
      • Create a Context – React.createContext()
      • Wrap the scope where the Context is need – <Context.Provider></Context.Provider>
      • Access/Listen Context
        • Consumer –
        • Hook
    • Limitations
      • Props for configuration, Context for state management across components (prevent long prop chain)
      • Not optimised for high frequency changes -> Redux
  • “Rules of Hooks”
    • Only call in React Functions
      • Component Functions, which returns JSX
      • Custom Hooks
    • Only call at the Top Level
      • Don’t call in nested functions
      • Don’t call in any block statement – condition or loop
    • Always add everything you refer to inside of useEffect() as a dependency
  • “Forward Refs”
    • useImperativeHandle() & React.forwardRef()
    • expose function in child component to parent component, use ref and function in child component in parent component

Section 12: How React Works

  • How does React work?
    • React – determines how the component tree currently looks like and what it should look like
    • ReactDOM – receives the differences and then manipulates the real DOM
  • Re-evaluating components !== re-rendering DOM
    • Components
      • re-evaluated whenever props, state or context changes
    • Real DOM
      • Only when there are differences between evaluations
  • React.memo()
    • Background – if a component is re-evaluated, all of its child components will also be re-evaluated.
    • Prevent unnecessary re-evaluations – check the changes in the props of component
    • At a cost, maintain a copy of props state and comparison
    • Chose wisely the appropriate component to use this function
  • Hook useMemo()
    • Stores data, while React.memo() stores function
    • Suitable for performance-intensive calculations
  • Hook useCallback()
    • Store a function across component executions
    • Otherwise the functions will be recreated each time the component is re-evaluated, which causes passing function props not working with React.memo()
    • Recreate the function when the dependency changed (?)
  • State Batching
    • when multiple states modified together, without time delay between modifications, React would batch them together and re-evaluate the component for once

Section 14: Class-based Components

  • Functional Components
    • Regular JS functions returns renderable result (JSX)
  • Class-based Components
    • JS classes, to-be-rendered output is defined in render() method
    • Prior to React < 16.8, Class-based components are mandatory to manage “State”
    • Can’t use React Hooks!
import { Component } from "react";

import classes from "./User.module.css";

class User extends Component {
  render() {
    return <li className={classes.user}>{this.props.name}</li>;
  }
}

// const User = (props) => {
//   return <li className={classes.user}>{props.name}</li>;;
// };

export default User;
  • Component Lifecycle (Classed-based Components only)
    • componentDidMount()
      • Called once when mounted (was evaluated & rendered)
      • useEffect(…, [])
    • componentDidUpdate()
      • Called once when updated
      • useEffect(…, [someValue])
    • componentWillUnmount()
      • Called right before unmounted
      • useEffect(() => {return () => {…}}, []) – clean up function
  • Error Boundaries
    • componentDidCatch()

Section 14: Sending Http Request

  • Fetch() API
    • response.json() – Promise
    • Data mapping
    • Error Handling
  function fetchMoviesHandler() {
    setIsLoading(true);
    fetch("https://swapi.dev/api/films/")
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        const transformedMovies = data.results.map((movieData) => {
          return {
            id: movieData.episode_id,
            title: movieData.title,
            openingText: movieData.opening_crawl,
            releaseDate: movieData.release_date,
          };
        });

        setMovies(transformedMovies);
        setIsLoading(false);
      });
  }

Section 15: Custom React Hooks

  • Outsource stateful logic into re-usable functions
  • Must start with “use-“
  • Just share the logic between components, not the actual state

Section 16: Forms & User Input

  • Forms and inputs can have different states
    • One or more inputs are invalid
      • Output input-specific error messages & highlight problematic inputs
      • Ensure form can’t be submitted / saved
    • All inputs are valid
      • Allow form to be submitted / saved
  • When to Validate?
    • When form is submitted
      • Avoid unnecessary warnings but present feedback “too late”
    • When a input is losing focus
      • Very useful for untouched forms
      • Use Ref
    • On every keystroke
      • Applied on invalid inputs to provide direct feedback
      • Use State – instant validation + reset
  • Validation – Client + Server
    • Custom input hook
  • Formilk Library

Section 18: Redux

  • A state management system for cross-component or app-wide state
  • Types of state
    • Local State
      • Belongs to a single component – “Show more”
      • useState() or useReducer()
    • Cross-Component State
      • Affects multiple components – Modal
      • “prop chains” or “prop drilling”
    • App-wide State
      • Affects the entire app – user authentication
      • “prop chains” or “prop drilling”
  • Context – potential disadvantages
    • Complex Setup / Management
    • Performance
  • Core Redux Concepts
    • The Reducer Function
      • Should be a pure function – same input leads to same output
      • Inputs: old state + dispatched action
      • Output: new state object
const redux = require("redux");

const counterReducer = (state = { counter: 0 }, action) => {
  if (action.type === "increment") {
    return {
      counter: state.counter + 1,
    };
  }
  return state;
};

const store = redux.createStore(counterReducer);

const counterSubscriber = () => {
  const latestState = store.getState();
  console.log(latestState);
};

store.subscribe(counterSubscriber);

store.dispatch({ type: "increment" });
import { useSelector, useDispatch } from "react-redux";

import classes from "./Counter.module.css";

const Counter = () => {
  const dispatch = useDispatch();
  const counter = useSelector((state) => state.counter);
  const toggleCounterHandler = () => {};

  const incrementHandler = () => {
    dispatch({ type: "increment" });
  };

  const decrementHandler = () => {
    dispatch({ type: "decrement" });
  };

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      <div className={classes.value}>{counter}</div>
      <div>
        <button onClick={incrementHandler}>Increment</button>
        <button onClick={decrementHandler}>Decrement</button>
      </div>
      <button onClick={toggleCounterHandler}>Toggle Counter</button>
    </main>
  );
};

// Class-based components
const mapStateToProps = state => {
  return {
    counter: state.counter
  };
}

const mapDispatchToProps = dispatch => {
  return {
    increment: () => dispatch({type: "increment"}),
    decrement: () => dispatch({type: "decrement"})
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(Counter);
  • Redux toolkit

Section 19: Advanced Redux

  • Reducers must be pure, side-effect free, synchronous functions
  • Where to put side-effects and async tasks?
    • Inside the components – useEffect()
    • Inside the action creators
  • Where to put logic code? – Fat Reducer, Fat Component or Fat Actions
  • Method “PUT” – overwrite data
  • What is a “Thunk”?
    • A function that delays an action until later -> An action creator function that does NOT return the action itself but another function which eventually returns the action

Section 20: Multi-Page SPA with React Router

  • What is Routing? – Traditional method
  • Routing in SPA
    • Page (URL) changes are handled by client-side (React) code
    • Changes the visible content without fetching a new HTML file
// index.js
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";

import "./index.css";
import App from "./App";

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);


// App.js
import { Route } from "react-router-dom";
import Welcome from "./components/Welcome";
import Products from "./components/Products";

function App() {
  return (
    <div>
      <Route path="/welcome">
        <Welcome />
      </Route>
      <Route path="/products">
        <Products />
      </Route>
    </div>
  );
}

export default App;
  • <Link> to replace <a>
  • <NavLink> to highlight active tag
    • <NavLink activeClassName={classes.active} to=”/welcome”>
  • Wrap <Route>s with <Switch> to restrict only one active route at one time, which matches first
    • attribute “exact”
  • Nested Routes
  • Redirecting
  • Query Parameters
    history.push(
      `${location.pathname}?sort=${isSortingAscending ? "desc" : "asc"}`
    );

// Equals

    history.push({
      pathname: location.pathname,
      search: `?sort=${isSortingAscending ? "desc" : "asc"}`,
    });
  • Upgrade from V5 to V6
    • <Switch> to <Routes>
    • Children component moved to “element” attribute
    • default “exact” match,
    • <NavLink> activeClassName attribute removed, manually check active status – navData.isActive ?
    • <Redirect> to <Navigate replace>
    • <Route> must be wrapped with <Routes>
    • Nested route
      • regular expression in parent path to allow nested routing
      • relative path to parent path in child components
    • useHistory() to useNavigate()
    • <Prompt> removed

Section 21: Deploying React Apps

  • Deployment steps:
    • Testing
    • Optimisation – lazy loading
    • Build for Production – npm run build
    • Upload Code to Server
    • Configure Server
  • Lazy loading
// import NewQuote from "./pages/NewQuote";

const NewQuote = React.lazy(() => import("./pages/NewQuote"));

// Add as sibling to <Switch> / <Routes>

      <Suspense
        fallback={
          <div className="centered">
            <LoadingSpinner />
          </div>
        }
      >

Section 22: Authentication

  • Authentication is needed if content should be protected (not accessible to everybody)
  • Authentication two-step process:
    • Get access/permission
    • Send request to protected resource
  • Server–side Sessions
    • Store unique identifier on server, send same identifier to client
    • Client sends identifier along with request to protected resources
  • Authentication Tokens (decoupled backend services)
    • Create (but not store) “permission” token with a specific algorithm on server, send token to client, but only the serve knows the private key
    • Client sends token along with requests to protected resources

Section 23: Next.js

  • What is NextJS?
    • React framework for production
    • A fullstack framework for ReactJS
  • Features:
    • Built-in server-side rendering
      • Improved SEO and initial load
      • Blending client-side and server-side: fetch data on the server and render finished pages
    • File-based Routing
      • Define pages and routes with files and folders instead of code
    • Fullstack Capailities
      • Easily add backend code
      • Storing data, getting data, authentication etc.
  • Nested Paths come with nested folder structure
  • Dynamic pages
    • [dynamicContent] in file name
    • import { useRouter } from “next/router”; router.query to extract info in path
  • Linking between pages
    • import Link from “next/link”; <Link> replace <a> to stay within the SPA
  • Page pre-rendering
    • Static generation
      • getStaticProps() to prepare data, only exist in server-side
      • revalidate: sec
      • getStaticPaths() in dynamic page to define which urls need to be pre-rendered
    • Server-side rendering
      • getServerSideProps(context)
      • run for every request
  • API Routes
    • import Head from “next/head”; to add meta data

Section 24: Animation

  • ReactTransitionGroup
    • <Transition>
      • in – boolean to indicate when to animate
      • timeout – could varies for in and out
      • mountOnEnter & unmountOnExit
    • <CSSTransition>
      • classNames – []-enter, []-enter-active,[]-exit, []-exit-active
    • <TransitionGroup> to animate list
  • Alternative animation packages
    • react motion
    • react move
    • react router transition

Section 25: Replace Redux with React Hooks

  • Context API
    • Suitable for state changing with low frequency – login status / theme selection
  • Custom Hook as a Store
    • Similar concept with npm package use-global-hook

Section 26: Automated Testing

  • What is “testing”?
    • Manual Testing:
      • Write code -> Preview & Test in Browser
      • Error-prone: hard to test all possible combinations and scenarios
    • Automated Testing:
      • Write extra code that tests your code
      • Test the individual building blocks of your app
      • Allows to test all building blocks at once
  • Categories – Unit Tests, Integration Tests and End-to-End (e2e) Tests
  • Required Tools & Setup
    • Tool for running tests and asserting the results
      • Jest
    • Tool for “simulating”(rendering) React app / components
      • React Testing Library
  • Write tests as close as possible to the component you want to test
  • Writing Tests – Three “A”s
    • Arrange – Set up the test data, test conditions and test environment
    • Act – Run logic that should be tested (e.g. execute function)
    • Assert – Compare execution result with expected results
  • Grouping Test with Test Suites
  • Testing Asynchronous Code
    • .getXXX() returns at once
    • findXXX() wait
  • Working with Mocks
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Greeting from "./Greeting";

describe("Greeting component", () => {
  test("renders 'Hello World' as a text", () => {
    // Arrange
    render(<Greeting />);

    // Act

    // Assert
    const helloWorldElement = screen.getByText("Hello World!");
    expect(helloWorldElement).toBeInTheDocument();
  });

  test("renders 'good to see you' if the buttuon was NOT clicked", () => {
    // Arrange
    render(<Greeting />);

    // Act

    // Assert
    const outputElement = screen.getByText("good to see you", { exact: false });
    expect(outputElement).toBeInTheDocument();
  });

  test("renders 'changed' if the buttuon was clicked", () => {
    // Arrange
    render(<Greeting />);

    // Act
    const buttonElement = screen.getByRole("button");
    userEvent.click(buttonElement);

    // Assert
    const outputElement = screen.getByText("Changed!");
    expect(outputElement).toBeInTheDocument();
  });
});

Section 27: React + TypeScript

  • “Superset” to JavaScript
    • Adds static typing to JS
  • Base Types
    • Primitives
      • number
      • string
      • boolean
    • String – Primitive[]
    • Object – {} and pre-defined structure
  • Type inference
  • Union Types string | number
  • Generics<T>

Leave a comment