banner
cos

cos

愿热情永存,愿热爱不灭,愿生活无憾
github
tg_channel
bilibili

Youth Training Camp | "Responsive Systems and React"

History and Applications of React#

Applications

  • Front-end application development, such as Facebook, Instagram, Netflix web version.
  • Mobile native application development, such as Instagram, Discord, Oculus.
  • Desktop application development in combination with Electron.

History

  • In 2010, Facebook introduced the xhp framework in its PHP ecosystem, which introduced the idea of compositional components and inspired the design of React.
  • In 2011, Jordan Walke created FaxJS, which later became the prototype of React:
    • It can be rendered on both the client and server sides.
    • Reactive, the UI automatically updates when the state changes.
    • Good performance, fast rendering.
    • Highly encapsulated components, function-based declaration.
  • In 2013, React was officially open-sourced, and Jordan Walke introduced this new framework, React, at the 2013 JSConf.
  • From 2014 to the present, there has been an explosion of the ecosystem, with various new tools/frameworks emerging around React.

Design Principles of React#

Pain Points of UI Programming#

  1. When the state is updated, the UI does not update automatically and requires manual DOM manipulation.
  2. Lack of basic code-level encapsulation and isolation, lack of componentization at the code level.
  3. Manual maintenance of data dependencies between UIs, which can lead to "Callback Hell" if the dependency chain is long.

Reactive and Transformative Systems#

Transformative system: Given an input, solve for the output, such as compilers, numerical calculations.

Reactive system: Listen for events, message-driven, such as monitoring systems, UI interfaces.

Event -> Execute predefined callback -> State change -> UI update

Reactive Programming and Componentization#

So we want to solve the above pain points:

  • State updates should automatically update the UI.
  • Front-end code should be componentized for reusability and encapsulation.
  • Declare the dependencies between states.

image.png

Componentization

  1. A component is either an atomic component or a combination of components.
  2. The component has internal state that is not visible externally.
  3. The parent component can pass state into the component to control the operation of the child component.

State Ownership#

The "current price" belongs to the Root node! Because it needs to be passed down, this is actually unreasonable, and this will be discussed in the state management library below.

The state should belong to the nearest common ancestor found by searching two (or more) nodes upward.

Considerations:

  1. Is React unidirectional or bidirectional data flow?

Answer: Unidirectional, where only the parent component passes things to the child component, but this does not mean that the child component cannot change the state of the parent component.

  1. How to solve the problem of state not being properly lifted?

Answer: Through a state management library, which will be discussed next.

  1. After the state of a component changes, how is the DOM updated?

Answer: This will be explained in the React implementation.

Component Design:

  • The component declares the mapping between state and UI.
  • The component has two types of properties: Props (external) and State (internal).
    • Props accept the state passed in by the parent component.
    • State is an internal property.
  • Can be composed of other components

Note: Students who have learned about mini-programs should know that the bi-directional binding of attributes in mini-programs actually uses this idea as well.

Lifecycle#

Mounting -> State update -> Unmounting

Writing React (Hooks)#

For information about React Hooks, please refer to the official documentation. The following content is mostly excerpted from: Hook Introduction - React (reactjs.org)

State Hook#

import React, {useState} from 'react';
function Example() {
	// Declare a state variable named "count".
	const [count, setCount] = useState(0);
    return (
        <div>
       		<p>You clicked {count} times</p>
			<button onClick={() => setCount(count + 1)}>
        		Click me
            </button>
        </div>
    );
}

The above function is used to display a counter, and when the button is clicked, the value of the counter will automatically increase.

In this example, useState is a Hook. It allows you to add some internal state to the component by calling it in a function component. React will preserve this state during re-renders. useState returns a pair of values: the current state and a function to update it. You can call this function from an event handler or other places.

The only argument to useState is the initial state. In the example above, our counter starts from zero, so the initial state is 0. It's worth noting that unlike this.state, the state here doesn't have to be an object —— if you have multiple values that need to be tracked, you can use an object or an array as the state. This initial state argument is only used during the first render.

Hooks are functions that let you "hook into" React state and lifecycle features from function components.

You can use the State Hook multiple times in a component:

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

Effect Hook#

Side effects refer to additional effects produced when a function is called, in addition to the return value. For example, modifying global variables (variables outside the function) or modifying parameters. A pure function is a function without side effects, which has been discussed in the JavaScript section.

For example, the following component sets a page title after React updates the DOM:

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Equivalent to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the page title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

When you call useEffect, you're telling React to run your "effect" function after flushing changes to the DOM. Because the effect function is declared inside the component, it has access to the component's props and state.

Rules of Using Hooks#

Hooks are JavaScript functions, but they have two additional rules:

  • Only call Hooks at the top level of a function. Don't call Hooks inside loops, conditions, or nested functions.
  • Only call Hooks from React function components. Don't call Hooks from regular JavaScript functions. (There is one more place where Hooks can be called —— inside custom Hooks)

Additionally, we provide a linter plugin to enforce these rules automatically. These rules might seem restrictive and confusing at first, but they are essential to ensure that Hooks work as intended.

The above is the official documentation of React.

React Implementation#

Three questions:

  1. JSX is not a syntax that conforms to the JavaScript standard.
  2. How to update the DOM when the returned JSX changes?
  3. How to trigger a re-render when the state/props are updated?

Problem 1#

The solution is simple, which is to convert JSX into valid JavaScript syntax.

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
// Equivalent to 
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

Problem 2#

The returned JSX itself is similar to DOM, but not DOM. DOM manipulation itself is very performance-intensive. Therefore, it is necessary to calculate a diff (difference) between the returned JSX and the original DOM structure. However, this diff algorithm itself cannot be too time-consuming, as small and short as possible.

Virtual DOM#

The Virtual DOM is an object maintained in memory in JavaScript that synchronizes with the real DOM and has a tree-like structure similar to the DOM and can establish a one-to-one correspondence with the DOM.

This approach gives React a declarative API: You tell React what state you want the UI to be in, and React ensures that the DOM matches that state. This allows you to free yourself from the necessary operations of attribute manipulation, event handling, and manual DOM updates during application development.

State update -> diff comparison between Virtual DOM and real DOM -> Re-render Virtual DOM to change our real DOM

How to Diff??#

Fewer updates <- Trade-off -> Faster computation speed

The perfect minimal diff algorithm requires O(n^3) complexity.

Instead, sacrificing the perfect minimal diff for time, we get an O(n) complexity algorithm that is locally optimal. Heuristic O(n) Algorithm.

  • Different types of elements -> Replace
  • DOM elements of the same type -> Update
  • Component elements of the same type -> Recursion

This algorithm only traverses once to calculate the diff.

However, this is also a drawback of React. When a component changes, all its child components will be re-rendered. To solve this problem, we need to look at the state management library in the next section.

React State Management Library#

Core Idea#

Extract the state from the UI and manage it externally, but this reduces the reusability of components, so this generally appears in business code. Any of the following frameworks can be used:

State Machine#

After receiving an external event, migrate to the next state based on the current state.

Which states are suitable for state management libraries?

  • States that may be used by many levels of components

Introduction to Application-Level Frameworks#

React itself does not provide enough engineering capabilities, such as routing, page configuration, etc.

  • Next.js - React Application Development Framework React development framework from Silicon Valley star startup Vercel, stable, good development experience, supports Unbundled Dev, sWC, etc. It also has a Serverless one-click deployment platform to help developers quickly complete deployment. The slogan is "Let's Make Web Faster".
  • Modern.js - Modern Web Engineering System (modernjs.dev) Full-stack development framework developed by ByteDance's Web Infra team, which includes many out-of-the-box capabilities and best practices, reducing the time spent on researching and selecting tools.
  • Get Started with Blitz (blitzjs.com) API-less full-stack development framework, no need to write API calls and CRUD logic during development, suitable for small teams with close collaboration between front-end and back-end.

Homework#

  1. Under what circumstances will the render function of a React component be re-executed?
  2. What are the advantages and disadvantages of React's functional programming compared to Vue's template-based front-end framework?
  3. React recommends using composition for component reuse instead of inheritance. What considerations are behind this?

Personal understanding

Summary and Thoughts#

This lesson provides a general introduction to React and its principles, as well as an introduction to componentization and some application-level frameworks.

Most of the content in this article is from Teacher Niu Dai's class and the React official documentation.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.