0%

React Course Notes

尚硅谷 React Course

React Basics

  1. React is a javascript library that can render HTML with data. It's not responsible for making requests or handling requests,it's only responsible for manipulating DOM

  2. React advantage

    • Using vanilla javascript to manipulate DOM is inefficient;manipulating DOM using javascript requires lots of DOM regeneration;
    • React uses component and declarative programming to improve efficienty;React Native can be used to make mobile apps;VDOM and the diffing algorithm reduces interaction with the real DOM
  3. An example

    • Related javascript library: react.development.jscore React library,react-dom.development.js core React DOM library,babel.min.js convert JSX to javascript that is recognizedby the browser

    • An example

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      <body>
      <div id="test"></div>
      <!-- Import react core, this must be imported before react-dom.development.js -->
      <script
      type="text/javascript"
      src="./javascript/react.development.js"
      ></script>
      <!-- Import react dome -->
      <script
      type="text/javascript"
      src="./javascript/react-dom.development.js"
      ></script>
      <!-- Import babel -->
      <script type="text/javascript" src="./javascript/babel.min.js"></script>

      <!-- Write JSX, the type must be text/babel -->
      <script type="text/babel">
      {/* 1. Create virtual DOM(VDOM)*/}
      const VDOM = <h1>Hello, React</h1>;
      {/* 2. Render VDOM to html page
      Two global variables: React from react core, ReactDOM from react-dom */}
      ReactDOM.render(VDOM, document.getElementById("test"));
      </script>
      </body>
    • You can use pure javascript to generate VDOM, in such case you do not need the babel library

      1
      2
      3
      4
      5
      6
      7
      8
      <script type="text/javascript">
      {/* 1. Create virtual DOM(VDOM)
      Equivalent to: const VDOM = <h1>Hello, React</h1>; with type="text/babel"*/}
      const VDOM = React.createElement("h1", { id: "title" }, "Hello React");
      {/* 2. Render VDOM to html page*/}
      Two global variables: React from react core, ReactDOM from react-dom*/}
      ReactDOM.render(VDOM, document.getElementById("test"));
      </script>

    • VDOM is actually a javascript object that has less attributes than the real DOM, it will be converted by React to the real DOM

  4. JSX

    • JavaScript XML, it's in essence the sugar for React.createElement(tag, attribute, children)
    • Syntax:
      • Use className to replace the class attribute in css(class is a keyword)
      • Use javascript expression(you cannot use javascript statements) {variable}
      • Use style={{k1:v1, ...,k2:v2}}(the outer curly braces specify inside is javascript code, the innder curly specifys the code is a javascript object)
      • VDOM can have only one root JXS tag
      • JSX tags must be have its closing tag or is self-closing
      • JSX tags with lowercase names will be converted by React to HTML tags with same names. If the first latter of a JSX tag is capatialized, it will be converted by React to JSX component
      • Working with arr in React: notice you need to provide a unique key for each item in the array, because React diffing algorithm utilizes keys to speed-up converting VDOM to real DOM. Using index as the unique key may cause error
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        <script type="text/babel">
        const arr = ["Angular", "Vue", "React"];
        const VDOM = (
        <ul>
        {arr.map((item, index) => (
        {/* Here is still JSX, so you need {item} */}
        <li key={index}>{item}</li>
        ))}
        </ul>
        );
        ReactDOM.render(VDOM, document.getElementById("test"));
        </script>

React Components

  1. Module and component

    • Module: reusable javascript file
    • Component: reusable html, css, js, img, video, ...
  2. React Developer Tools Chrome extension

  3. Functional component

    • An example
      1
      2
      3
      4
      5
      6
      7
      8
      9
      <script type="text/babel">
      {/* 1. Create a functional component, the first letter should be
      capitalized so the it will be regarded as a JSX component */}
      const Mycomp = () => {
      return <h1>Hello, React</h1>;
      };
      {/* 2. Render the component with component tag */}
      ReactDOM.render(<Mycomp />, document.getElementById("test"));
      </script>
    • Notice the this inside user-defined component is undefined, because the code will be translated by babel into javascript, and use strict will be added to the code during translation> In strict mode, this inside user-defined function is not allowed to point to the window obejct
    • Logic of functional component: ReactDom.render() will call the function that defines the functional component, get the VDOM returned by the function, and then inserts the VDOM into the real DOM on the html page
  4. Class component

    • An example
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      <script type="text/babel">
      {/* 1. Create a class that extends React.Component, override render method,
      return VDOM inside render method */}
      class Mycomponent extends React.Component {
      render() {
      return <h1>Hello, React</h1>;
      }
      }
      {/* 2. Render the component with component tag */}
      ReactDOM.render(<Mycomp />, document.getElementById("test"));
      </script>
    • Logic of class component: ReactDom.render() recognizes the name of the class component, creates an instance of such type, calls the render method on the instance and gets its returned VDOM, and then inserts the VDOM into the real DOM on the html page
    • Three main attributs of class component instance: props, refs, state. With hooks, functional components can also have these there attributes
    • Simple component: does not have state, complex component: has state
  5. State attribute

    • State: state is used to store property values that belongs to the component, when the state object changes, the component re-renders

    • State example

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      <script type="text/babel">
      {/* 1. Create a class that extends React.Component, override render method,
      return VDOM inside render method */}
      class Mycomponent extends React.Component {
      constructor(props) {
      super(props);
      this.state = {
      hot: true,
      };
      {/* this.changeHot is a field
      this.click is a method on prototype
      this.click.bind(this) binds the click on prototype with this(here this is the Mycomponent instance) */}
      this.changeHot = this.click.bind(this);
      }

      {/* this method is on prototype of Mycomponent */}
      click() {
      this.setState({ ...this.state, hot: !this.state.hot });
      }

      render() {
      return (
      {/* You shoul use this.click instead of click, otherwise the this object inside click method will be undefined
      Logic: 1. onClick = this.click, pass ref of click to onClick
      2. directly call onClick when button is pressed, since the method call is not inside Mycomponent, the this
      object does not point to Mycomponent instance. But at the same time, this does not point to window, because
      local use strict mode is auto enfored in for class methods, and then this object there are not allowed to
      point to window */}
      <h1 onClick={this.changeHot}>
      Today is {this.state.hot ? "Hot" : "Cold"}
      </h1>
      );
      }
      }
      {/* 2. Render the component with component tag */}
      ReactDOM.render(<Mycomponent />, document.getElementById("test"));
      </script>
    • State example without constructor and using assignment for instance fields and instance methods

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <script type="text/babel">
    class Mycomponent extends React.Component {
    {/* initialize state */}
    state = { hot: true };
    {/* defined user method: commonly used for callback */}
    click = () => {
    this.setState({ ...this.state, hot: !this.state.hot });
    };

    render() {
    return (
    <h1 onClick={this.click}>
    Today is {this.state.hot ? "Hot" : "Cold"}
    </h1>
    );
    }
    }
    ReactDOM.render(<Mycomponent />, document.getElementById("test"));
    </script>
  6. Props attributes

    • Props: props are arguments passed into React components using HTML attributes

    • Props are readonly values, you can do computation on props but you cannot modify prop values

    • Simple props example

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      <div id="test1"></div>
      <div id="test2"></div>
      <div id="test3"></div>

      <script type="text/babel">
      class MyComponent extends React.Component {
      render() {
      const { name, age, sex } = this.props;
      return (
      <ul>
      <li>{name}</li>
      <li>{age}</li>
      <li>{sex}</li>
      </ul>
      );
      }
      }
      ReactDOM.render(
      <MyComponent name="test_name_1" age="test_age_1" sex="test_sex_1" />,
      document.getElementById("test1")
      );
      ReactDOM.render(
      <MyComponent name="test_name_2" age="test_age_2" sex="test_sex_2" />,
      document.getElementById("test2")
      );
      ReactDOM.render(
      <MyComponent name="test_name_3" age="test_age_3" sex="test_sex_3" />,
      document.getElementById("test3")
      );
      </script>
    • Props using spread syntax(...) in JSX tag

      • In pure javascript, ... cannot be used to spread an object, it can only bed used to make a deep copy of an object
        1
        2
        3
        4
        5
        const obj1 = { a: 1, b: 2 };
        console.log(...obj1); {/* error */}
        const obj2 = { ...obj1 }; {/* make a deep copy of obj1 */}
        obj1.a = 2;
        console.log(obj2.a); {/* 1 */}
      • With babel and React core, you can use ... to spread object in JSX
      • An example
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        <script type="text/babel">
        class MyComponent extends React.Component {
        render() {
        const { name, age, sex } = this.props;
        return (
        <ul>
        <li>{name}</li>
        <li>{age}</li>
        <li>{sex}</li>
        </ul>
        );
        }
        }
        const obj1 = {
        name: "test_name_1",
        age: "test_age_1",
        sex: "test_sex_1",
        };
        const obj2 = {
        name: "test_name_2",
        age: "test_age_2",
        sex: "test_sex2",
        };
        const obj3 = {
        name: "test_name_3",
        age: "test_age_3",
        sex: "test_sex_3",
        };
        ReactDOM.render(
        <MyComponent {...obj1} />,
        document.getElementById("test1")
        );
        ReactDOM.render(
        <MyComponent {...obj2} />,
        document.getElementById("test2")
        );
        ReactDOM.render(
        <MyComponent {...obj3} />,
        document.getElementById("test3")
        );
        </script>
    • Props type constraints and default values

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      <!-- Import PropTypes to make constraints on props types -->
      <script type="text/javascript" src="../javascript/prop-types.js"></script>
      <script type="text/babel">
      {/* Write outside MyComponent class */}
      MyComponent.propTypes = {
      {/* For React version <= 15, use React.PropTypes instead of PropTypes */}
      name: PropTypes.string.isRequired,
      age: PropTypes.number,
      sex: PropTypes.string,
      {/* PropTypes.func requires that the feild should be a method */}
      };
      MyComponent.defaultProps = {
      age: 17,
      sex: "male",
      };
      </script>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      <!-- Import PropTypes to make constraints on props types -->
      <script type="text/javascript" src="../javascript/prop-types.js"></script>
      <script type="text/babel">
      {/* Write inside MyComponent class */}
      class MyComponent extends React.Component {
      static propTypes = {
      {/* For React version <= 15, use React.PropTypes instead of PropTypes */}
      name: PropTypes.string.isRequired,
      age: PropTypes.number,
      sex: PropTypes.string,
      {/* PropTypes.func requires that the feild should be a method */}
      };
      static defaultProps = {
      age: 17,
      sex: "male",
      };
      }
      </script>

    • Constructor and props

      • Typically, in React constructors are only used for two purposes:
        • Initializing local state by assigning an object to this.state, can be done without a constructor
        • Binding event handler methods to an instance, can be done without a constructor
      • So removing the constructor is totally fun
      • If you write a constructor and pass props to it, then you need to call super(props) at the first line of the constructor, otherwise this.props will be undefined inside the constructor
    • Working with props in functional components

      • Since function accepts arguments, you can use functional components to accept props
      • An example
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        <script type="text/babel">
        const MyComponent = (props) => {
        const { name, age, sex } = props;
        return (
        <ul>
        <li>{name}</li>
        <li>{"Age: " + (parseInt(age) + 1)}</li>
        <li>{"sex: " + sex}</li>
        </ul>
        );
        };
        {/* propTypes and defaultProps have to be outside the function */}
        MyComponent.propTypes = {
        name: PropTypes.string.isRequired,
        age: PropTypes.number,
        sex: PropTypes.string,
        };
        MyComponent.defaultProps = {
        age: 17,
        sex: "male",
        };
        const obj1 = {
        name: "test_name_3",
        };
        ReactDOM.render(
        <MyComponent {...obj1} />,
        document.getElementById("test1")
        );
        </script>
      • Without hooks, functional components can only work with props, but not state and refs
  7. Refs attribute

    • Refs provide a way to access DOM nodes or React elements created in the render method, it's similar to id attribute in javascript
    • Use this.refs.name to get the corresponding node
    • String refs(not recommended due to efficiency issues) example:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      <script type="text/babel">
      class MyComponent extends React.Component {
      showData1 = () => {
      const input1 = this.refs.input1;
      alert(input1.value);
      };
      showDate2 = () => {
      const input1 = this.refs.input2;
      alert(input1.value);
      };
      render() {
      return (
      <div>
      <input ref="input1" type="text" placeholder="Input some data" />{" "}
      <button onClick={this.showData1}>Click to alert input</button>
      <input
      ref="input2"
      type="text"
      placeholder="Input some data"
      onBlur={this.showDate2}
      />
      </div>
      );
      }
      }
      ReactDOM.render(<MyComponent />, document.getElementById("test"));
      </script>
    • Callback refs example: bind current to a field of the class instance. For inline ref callbacks, each rerender will let the callback be executed twice(first with null and then again with the DOM element), you can use a class function to avoid this
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      <script type="text/babel">
      class MyComponent extends React.Component {
      showData1 = () => {
      alert(this.input1.value);
      };
      saveInput = (currentNode) => {
      this.input1 = currentNode;
      }
      render() {
      return (
      <div>
      {/* In callback ref = {c => this.input1 = c}, c is the current node,
      and this is an instance of the current class. This inline callback will be executed twice during rerener*/}
      <input
      ref = {this.saveInput}
      {/*
      ref={(currentNode) => {
      this.input1 = currentNode;
      }}
      */}
      type="text"
      placeholder="Input some data"
      />
      <button onClick={this.showData1}>Click to alert input</button>
      </div>
      );
      }
      }
      ReactDOM.render(<MyComponent />, document.getElementById("test"));
      </script>
    • Use React.createRef()
    • This method returns a container, when pointed to by the ref attribute of a node, it will return a container with the current node inside
    • Use React.createRef().current to get the node inside the container
    • The container can hold only one node, node that is referenced later will replace node that is saved earlier. So you need to create a container for each node
    • An example
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      <script type="text/babel">
      class Mycomponent extends React.Component {
      state = { hot: true };
      click = () => {
      this.setState({ hot: !this.state.hot });
      };
      showData = () => {
      alert(this.myRef.current.value);
      };
      myRef = React.createRef();

      render() {
      return (
      <div>
      <h1>Today is {this.state.hot ? "Hot" : "Cold"}</h1>
      <input
      ref={this.myRef}
      type="text"
      placeholder="input value"
      />
      <button onClick={this.click}>Change hot</button>
      <button onClick={this.showData}>Show value</button>
      </div>
      );
      }
      }
      ReactDOM.render(<Mycomponent />, document.getElementById("test"));
      </script>
  8. Event Handling

    • React events are named using camelCase, rather than lowercase, because react repackages built-in javascript events (in lowercase) to increase compatibility
    • React events are popped up to the outmost node to improve efficiency
    • Use event.target to get the source node when the node that has event is the same as the target node you want to manipulate, do not overuse ref in situation like this
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      <script type="text/babel">
      class Mycomponent extends React.Component {
      myRef = React.createRef();
      showData = () => {
      alert(this.myRef.current.value);
      };

      render() {
      return (
      <div>
      <h1>Test</h1>
      <input
      {/* Actually we do not need the ref here */}
      ref={this.myRef}
      onBlur={this.showData}
      type="text"
      placeholder="input value"
      />
      </div>
      );
      }
      }
      ReactDOM.render(<Mycomponent />, document.getElementById("test"));
      </script>
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      <script type="text/babel">
      class Mycomponent extends React.Component {

      {/* Pass the blur event into the method and use it the get the node*/}
      showData = (event) => {
      alert(event.target.value);
      };

      render() {
      return (
      <div>
      <h1>Test</h1>
      <input
      onBlur={this.showData}
      type="text"
      placeholder="input value"
      />
      </div>
      );
      }
      }
      ReactDOM.render(<Mycomponent />, document.getElementById("test"));
      </script>
    • Uncontrolled component: component that stores its own state internally, its value can be found using ref.current.value when you need it
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      <script type="text/babel">
      class Mycomponent extends React.Component {
      myRef1 = React.createRef();
      myRef2 = React.createRef();
      myRef3 = React.createRef();
      showData = (event) => {
      // prevent form default behavior
      event.preventDefault();
      alert(
      // Use ref to get the value of input when you need it
      `Username: ${this.myRef1.current.value}, email: ${this.myRef2.current.value}, password: ${this.myRef3.current.value}`
      );
      };
      render() {
      return (
      <div className="col-6 offset-3">
      <form
      action="https://www.google.com"
      method="get"
      onSubmit={this.showData}
      >
      <div className="form-group">
      // Use htmlFor instead for
      <label htmlFor="username">Username</label>
      <input
      type="text"
      className="form-control"
      id="username"
      placeholder="Enter email"
      name="username"
      ref={this.myRef1}
      />
      </div>
      <div className="form-group">
      <label htmlFor="email">Email address</label>
      <input
      type="email"
      className="form-control"
      id="email"
      aria-describedby="emailHelp"
      placeholder="Enter email"
      name="email"
      ref={this.myRef2}
      />
      <small id="emailHelp" className="form-text text-muted">
      We'll never share your email with anyone else.
      </small>
      </div>
      <div className="form-group">
      <label htmlFor="password">Password</label>
      <input
      type="password"
      className="form-control"
      id="password"
      placeholder="Password"
      name="password"
      ref={this.myRef3}
      />
      </div>
      <button type="submit" className="btn btn-primary">
      Submit
      </button>
      </form>
      </div>
      );
      }
      }
      ReactDOM.render(<Mycomponent />, document.getElementById("test"));
      </script>
    • Controlled component: one that takes its current value through props and notifies changes through callbacks like onChange. A parent component "controls" it by handling the callback and managing its own state and passing the new values as props to the controlled component, the usage of value and onChange is similar to Vue v-model two-way binding
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      <script type="text/babel">
      class Mycomponent extends React.Component {
      state = {
      username: "",
      password: "",
      email: "",
      };
      // Higher order function to reduce code redundancy
      saveFormdata = (type) => {
      return (event) => {
      this.setState({
      ...this.state,
      // type is a string, you cannot simply write type: event.target.value
      [type]: event.target.value
      });
      };
      };

      showData = (event) => {
      event.preventDefault();
      alert(
      `Username: ${this.state.username}, email: ${this.state.email}, password: ${this.state.password}`
      );
      };
      render() {
      return (
      <div className="col-6 offset-3">
      <form
      action="https://www.google.com"
      method="get"
      onSubmit={this.showData}
      >
      <div className="form-group">
      <label htmlFor="username">Username</label>
      <input
      type="text"
      className="form-control"
      id="username"
      placeholder="Enter email"
      name="username"
      onChange={this.saveFormdata("username")}
      value={this.state.username}
      />
      </div>
      <div className="form-group">
      <label htmlFor="email">Email address</label>
      <input
      type="email"
      className="form-control"
      id="email"
      aria-describedby="emailHelp"
      placeholder="Enter email"
      name="email"
      // Another approach without HOF
      // on change={event => {this.saveData("email", event)}}
      onChange={this.saveFormdata("email")}
      value={this.state.email}
      />
      <small id="emailHelp" className="form-text text-muted">
      We'll never share your email with anyone else.
      </small>
      </div>
      <div className="form-group">
      <label htmlFor="password">Password</label>
      <input
      type="password"
      className="form-control"
      id="password"
      placeholder="Password"
      name="password"
      onChange={this.saveFormdata("password")}
      value={this.state.password}
      />
      </div>
      <button type="submit" className="btn btn-primary">
      Submit
      </button>
      </form>
      </div>
      );
      }
      }
      ReactDOM.render(<Mycomponent />, document.getElementById("test"));
      </script>
  9. Component Lifecycle

    • Delete a component: ReactDOM.unmountComponentAtNode(document.getElementById<nodeName>))
    • Mount: insert VDOM into real DOM, unmount: detach VDOM from real DOM
    • When ReactDOM.render() is called:
      • for the first time VDOM is mounted onto the real DOM
      • for each time the state is changed
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        <script type="text/babel">
        class Mycomponent extends React.Component {
        state = { opacity: 1 };
        // Delete a component
        detach = () => {
        ReactDOM.unmountComponentAtNode(document.getElementById("test"));
        };
        // Call this method once when VDOM is mounted to the real DOM
        componentDidMount() {
        // Start timer
        this.timer = setInterval(() => {
        let opacity = this.state.opacity;
        opacity -= 0.1;
        if (opacity <= 0) {
        opacity = 1;
        }
        this.setState({
        opacity: opacity,
        });
        }, 200);
        }
        // Call this method before VOM is deleted
        componentWillUnmount() {
        // Clear the timer
        clearInterval(this.timer);
        }

        render() {
        return (
        <div>
        <h2 style={{ opacity: this.state.opacity }}>
        This is a changing heading
        </h2>
        <button onClick={this.detach}>Detach component</button>
        </div>
        );
        }
        }
        ReactDOM.render(<Mycomponent />, document.getElementById("test"));
        </script>
    • Original lifecycle hooks
      • Mount: constructor(), componentWillMount(), render(), componentDidMount()(initialization: setInterval, send request, subscribe message)
      • UnMount: componentWillUnmount()(finalization: clear interval, unsubscribe message), then ReactDOM.unmountComponentAtNode() is called
      • Update: if this.setState() is called, shouldComponentUpdate() (by default this method returns true), componentWillUpdate(), render(), componentDidUpdate()
      • Force update: forceUpdate() is called (state is not changed), componentWillUpdate(), render(), componentDidUpdate()
      • Parent component passes props to child component and parent change state: parent calls this.setState(), child calls componentWillReceiveProps()(for the first time, this method is not called but actually the child component did receive props from its parent), then child calls shouldComponentUpdate(), then child calls componentWillUpdate(), then child calls render(), then child calls componentDidUpdate()
    • Current lifecycle hooks
      • Deprecated: componentWillMount changed to UNSAFE_componentWillMount, componentWillUpdate changed to UNSAFE_componentWillUpdate, componentWillReceiveProps changed to UNSAFE_componentWillReceiveProps. The above methods are often misused and maybe have bugs with newer React async rendering
      • Introduce two new callbacks: static getDerivedStateFromProps()(if state always depends on props, use this), getSnapshotBeforeUpdate(), but these two are rarely used
  10. React DOM Diffing algorithm

    • The minimum granularity for diffing algorithm is a tag(for nested tags, only consier the changed layer and its components)
    • What does list li tag key do
      • When there is new data, React will generate new VDOM for all data
      • The React uses diffing algorith to compare the old VDOM and new VDOM
        • If a key exists in both, then checks data, if data are the same, then new change will be made, if data are different, a new real DOM is generated and then used to replace the old real DOM
        • If a key only exists in new VDOM, a new real DOM is generated and then used to replace the old real DOM
    • What is the problem of using array index as key: index does not uniquely identify elements. In cases where the array is sorted or an element is added to the beginning of the array, the index will be changed even though the element representing that index may be the same. In some cases where you only need to display the contents, using id does not cause problems

React Scaffold

  1. React scaffold
    • React official team provides a library to create a React template project based on React Scaffold. This library is based on Webpack
    • Installation: npm i -g create-react-app
    • Create an app: create-react-app <apName>
    • Start app: npm start or yarn start
  2. The template project
    • Project structure
      • /public/index.html is the root html page, and there should be only one html page in the public folder
      • /src/App.js the main JSX file, index.html root tag should only the APP module
      • /src/index.js entrance file, the <React.StrictMode> is a tool that highlights potential issues in a programme (like deprecated callbacks, unrecommended bahaviors, etc.)
      • /src/reportWebVitals.js used for monitor page performance
      • /src/setupTests.js used for testing components
    • Execution logic: index.js include App.js, then render component into index.html
    • An update in React 18: ReactDOM.render is no longer supported, use the following code instead
      1
      2
      3
      4
      5
      6
      const root = ReactDOM.createRoot(document.getElementById('root'));
      root.render(
      <React.StrictMode>
      <App />
      </React.StrictMode>
      );
  3. Create a project
    • Write your own /public/index.html, /src/index.js, /src/APP.js
    • Notice if your VS Code autocomplete is not working in the React Project, change the file language from JavaScript to JSX
    • Structure: for component Hello.js and Hello.css, they should be placed inside /src/components/Hello/
    • For component javascript files, you can use Name.jsx instead of Name.js
    • Sometimes for component Hello, the file structure is /src/components/Hello/index.jsx, if you use index.js or index.jsx like this, when you want to import the component, you can use import /src/components/Hello instead of import /src/components/Hello/Hello
    • CSS modularity
      • There can be conflicts among css files from different modules, one way to solve the proble is to use less, another is to modular css
      • Modular css works with all css selectors, for example if you have #pg1 and object hello, you simply write hello.pg1
      • An example, suppose you have a module called Hello, inside it you have index.css and index.jsx, first rename the css file to index.module.css, then you can import it in the jsx file like this:
        1
        2
        3
        4
        5
        // previously you write import "./index.css"
        // this hello object can hold the properties defined inside the css file
        import hello from "./index.module.css";

        <h1 className={hello.heading}>Text </h1>
  4. VS Code React extension
    • Snippets, full link of snippets
      • rcc/ rce: create component class
      • rfc: create functional component
      • imr: import React, imrd: import ReactDOM
      • ptsr: PropTypes.string.isRequired
      • imp: import A from B
      • ......
  5. General steps:
    • Split page into components
    • Create static components
    • Create dynamic components: dynamically render data, include user interaction
  6. Todo Project
    • When you use a customized component <Item> as a list item, the component itself should have an id, the <li> inside does not need to have a tag
    • Child wants to access parent state: parent passes the state in props
    • Child wants to modify parent state: parent passes a callback in props, child change parent state in the callback
    • Some event: onKeyUp, onMouseLeave, onMouseEnter
    • Does not display a component: style={{display:"none"}}
    • In order to use confirm(msg) in React, you should write window.confirm(msg)

React Ajax

  1. React focuses on page layout, it does not contain code for ajax request. You can use axios(recommended) or jquery to send ajax requests

  2. By default, ajax does not allow CORS, if you cannot change server response header settings, then you need to configure proxy in your react project

  3. You need to use Octokit.js to use the GitHub REST API

  4. Direct communication between sibling components via the pubsub-js library

  • npm install pubsub-js
  • Example
    1
    2
    3
    4
    5
    6
    7
    import PubSub from 'pubsub-js';
    // Publisher
    PubSub.publish('topic', data);
    // Subscriber
    PubSub.sucribe('topic', (msg, data) => {
    console.log(data);
    });

React Router

  1. SPA(single page web application): this application contains only one page, it only re-renders part of its page to display contents from different components

  2. Router

  • A router is in essence a mapping from path to either a function (backend router)or a component(frontend router)
  • Frontend router is based on manipulation of browser history
  • For web development, use react-router-dom, for application development, use react-router-native
  1. Main topics
  • The page should be managed by one and only one router, either a BrowserRouter or a HashRouter, so you can simply wrap the App component with the BrowserRouter
  • Use <Link to=""> in react to replace <a> in html
  • Use <Route path="" component="" /> to create mapping between route and component
  • Example
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    import React, { Component } from "react";
    import { Link, BrowserRouter, Route } from "react-router-dom";
    import About from "./components/About";
    import Home from "./components/Home";

    import app from "./App.module.css";

    export default class App extends Component {
    render() {
    return (
    <BrowserRouter>
    <div className={app.container}>
    <h1>This APP</h1>
    <div className={app.navRouter}>
    <Link to="/about" className={app.link}>
    About
    </Link>
    <Link to="/home" className={app.link}>
    Home
    </Link>
    </div>
    <div className={app.display}>
    <Route path="/about" component={About} />
    <Route path="/home" component={Home} />
    </div>
    </div>
    </BrowserRouter>
    );
    }
    }
  • For route components, place them inside pages directory instead of components directory
  • Compared with ordinary components, components inside <Route> can receive props passed by Router: location, history, match, and more
  • If you want to add additional styling attributes to link, use <NavLink> instead, navlink knows if a link is active or pending, you can use activeClassName to modify styling of active links
  • You can encapsulate NavLink to customize styling, to receive the tag body, use this.props.children
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import React, { Component } from "react";
    import { NavLink } from "react-router-dom";
    import link from "./index.module.css";

    export default class MyNavLink extends Component {
    render() {
    return (
    // <NavLink
    // activeClassName={link.active}
    // className={link.link}
    // {...this.props}
    // >
    // To receive tag body, use this.props.children
    // {this.props.children}
    // </NavLink>

    // This approach is more concise
    <NavLink
    activeClassName={link.active}
    className={link.link}
    {...this.props}
    />
    );
    }
    }
  • Use <Switch></Switch> to wrap <Route/> to require that only one(this first one) component could be matched by one path. Otherwise for a specific path, react will search all Route components and render all pages whose path attribute equals to that path
  • For multi-layer route, BrowRouter may cause errors in static erros, there are multiple ways to solve this:
    • Use absolute path instead of relative path for static resources(the root is the public directory in your project), this works w/ react scaffold
    • Append %PUBLIC_URL% to static resource paths, this only works within react scaffold
    • Use HashRouter instead of BrowserRouter, because paths after the # are only recognized as hash values instead of actual urls
  • Ambiguous match: the to attribute in Link can contain the path attribute in Route, by default path in Route enables ambiguous match, if you want to use exact match, use exact or exact={true} in Route. Do not enable exact match unless it causes errors in your project
  • Use Redirect to redirect "/" to a specific page
    1
    2
    3
    4
    5
    6
    <Switch>
    <Route path="/about" component={About} />
    <Route path="/home" component={Home} />
    // By default home page is selected, and the default url will be hostname:port/home instead of hostname:port
    <Redirect to="/home" />
    </Switch>
  • For multi-layer route, the logic is the same, just use <NavLink> and <Route>
  • Add replace to link to change from push routing to replace routing
  1. Route data passing
  • Use params to pass data: use this.props.match.params to get received data
    1
    2
    3
    4
    5
    6
    // Pass params data like this in Link
    <Link to={`/home/msg/detail/${item.id}`}>{item.id}</Link>
    // Declare that there is params data passed when registering route
    <Route path={`/home/msg/detail/:id`} component={Detail}/>
    // Use params data like this in Detail
    const {id} = this.props.match.params;
  • Use search to pass data
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // Pass search data like this in Link
    <Link to={`/home/msg/detail/?id=${item.id}`}>{item.id}</Link>
    // No need to declare anything here for search data
    <Route path={`/home/msg/detail`} component={Detail}/>
    // Use data like this in Detail, the location.search is a string that looks like this: "?id=1&k1=v1&k2=v2"
    // You can manually get the id like this
    const {id} = this.location.search.split("&")[0].substr(1).split("=")[1];
    // You can also rely on the queryString library
    import qs from 'queryString'
    // Remove the question mark
    const query = this.location.search.substr(1);
    // qs.parse(str) converts URL encoded string to object, qs.stringfy(obj) converts object to URL encoded string
    const {id} = qs.parse(query);
  • Use state attribute of Route tag to pass data
    1
    2
    3
    4
    5
    6
    // Pass state data like this in Link, here you need to pass an object to the to attribute
    <Link to={{pathname: "/home/msg/detail", state: {id: item.id}}}>{item.id}</Link>
    // No need to declare anything here for state data
    <Route path={"/home/msg/detail/"} component={Detail}/>
    // Use state data like this in Detail
    const {id} = this.props.location.state;
  1. Page routing without Link/NavLink
  • Add event listener, then call this.props.history.push(pathname) or this.props.history.replace(pathname)
  • For pathname with params data or search data, just modify the pathname
  • For state data, just use push(pathname, state), replace(pathname, state)
  • Use this.props.history.goBack(), this.props.history.goForward() to either go back or go forwward, this.props.history.go(n) can either go forward n steps with positive n or back n steps with negative n
  • Timed page routing: add page routing inside a timer method in componentDidMount()
  1. Use routing in ordinary components
  • In react only route components have attributes like history, match, location, other ordinary components do not have these attributes
  • You can use withRouter to enable ordinary components have route component APIs
    1
    2
    3
    4
    5
    import {withRouter} from "react-router-dom";

    class Demo extends Component {}

    export default withRouter(Demo);

React UI library

  1. Common UI library: MUI, Ant Design(AntD)
  • MUI: npm install @mui/material @emotion/react @emotion/styled
  • Ant Design: npm install antd

Redux

  1. Introduction
  • Redux is a pattern and library for managing and updating application state, using events called actions
  • Installation Redux Toolkit(RTK): npm install @reduxjs/toolkit and the complementary package: npm install react-redux
  1. Core concepts
  • Action: a plain JavaScript object that has a type string field, data is stored in the payload field
  • Action creator: a function that creates and returns an actiopn object
  • Reducer: a function that receives the current state and an action object, decides how to update the state if necessary, and returns the new state(cannot modify the current state in place)
  • Store: store contains the application states, it's created by passing a reducer, and has a method called getState to return the current state
  • Dispatch: store.dispatch(action) is the only way to update states
  • Selector: function that knows how to extract specfic information from a store state value