preface

  • I talked earlier in Vue components about why componentization, what is componentization, and I won’t go into that again. Okay
  • Unlike Vue, React doesn’t have SFC(.vue), its components are just JS files.
  • React components come in two types: class components and function components. They both have different features and are written differently. Let’s take a look at class components

The basic use

  1. Creating a static view
  2. Break up the component
  3. Linked data
  4. Processing state

Component calls

  • Call through JSX, note that the first letter of the component must be uppercase – use the big camel name
import App from './App'
ReactDOM.render(
  <App></App>.document.querySelector('#root'))Copy the code

Components to create

  1. When using a class component, you must inherit fromReact.Component
  2. The class component must have a React method (introducing react) that defines the view the component is building in the return of Render
  3. You need to export components
import React, { Component } from 'react';

export default class App extends Component {
    render() {
        return <div></div>}}Copy the code

PureComponent

  • React has a much-maligned performance problem. When a state changes, all components are vNodes depending on that state, no matter how big
    • Doesn’t diff calculate the difference in the component’S DOM tree when it changes state, find the DOM that actually changed, and render part of it?
    • The problem with this statement is that it does not actually change the page view, but it will regenerate the vNodes and diff of all components that depend on this state, which will undoubtedly increase the performance cost
    • In addition, Vue2 will have at least one Watcher for each component to observe the state changes of each component, without rendering the entire component tree
  • So how do we optimize him? ShouldComponentUpdate can be used to compare before and after to prevent component updates
class Child extends Component {
    shouldComponentUpdate(nextProps, nextState) {
        // Write the outline here, depending on the actual project
        return! (nextProps ===this.props && nextState === this.state)
    }
    render() {
        return <div></div>}}Copy the code
  • That seems like a lot of trouble to write all of them. Is there an easier way? usePureComponentIt can help you cut down on your workload
  • PureComponentInternal provides a shallow contrast between state and props, and other functionsComponentThe same
  • And it’s worth noting becausePureComponentAs a pre-comparison, if the data is of a complex type, a new reference needs to be returned, otherwise the component will not be updated, and we can do this conveniently using the deconstruction syntax
import React, { PureComponent } from 'react'

class Child extends PureComponent {
    render() {
        return <div></div>}}Copy the code

Component view update – state

  • The React view update is similar to a state machine: what does it look like when the state is there
  • Class components use state to manage view updates – use state to store the component’s own data
  • Updating state with setState causes component updates (view rerendering)
  • SetState takes two arguments:
    • Updater: Updates data FUNCTION/OBJECT
    • Callback: callback FUNCTION after a successful update
  • SetState has two characteristics:
    • Asynchronous: React usually aggregates a batch of components that need to be updated and then updates them all at once to ensure performance
    • Shallow merge: Shallow merge will happen, we just need to modify the state we need to modify – objecr.assign ()
  • After calling setState, the lifecycle is triggered to re-render the component
import React, { Component } from 'react';

class App extends Component {
    state = {
        count: 1.name: 'milk'
    }
    render() {
        console.log('Ready to render/update components');
        let { count, name } = this.state;
        return (
            <div>
                <p>name: {name}</p>
                <p>count: {count}</p>
                <button onClick={()= >{ // object this.setState({ name: 'newMilk' }); // function this.setState(() => {count} ++ return {count}}, () => {console.log(' component updated '); }); Increasing}} ></button>
            </div>)}}Copy the code

Class component events

  • Note that the event name is Little Hump
  • Because events in JSX are not actually called by the class itself, it is important to change this, which is undefined by default for event handlers
  • Resolve this by binding this
class App extends Component {
    constructor(props) {
        super(props)
        this.state = {
            count: 1
        }
        // Use bind to change this reference
        this.handleClick = this.handleClick.bind(this)}handleClick() {
        console.log(this);
    }
    render() {
        let { count } = this.state
        return (
            <div>
                <p>{count}</p>
                <button onClick={this.handleClick}>increasing</button>
            </div>)}}Copy the code
  • Use arrow function syntax
class App extends Component {
    state = {
        count: 1
    }
    handleClick = () = > {
        console.log(this);
    }
    render() {
        let { count } = this.state
        return (
            <div>
                <p>{count}</p>
                <button onClick={this.handleClick}>increasing</button>
            </div>)}}Copy the code

Inter-component communication – props

  • Information is passed between components
    • Father the son:
      • When the parent component calls the child component, it adds data to the properties of the child component, which then gets the data passed by the parent from the props property
    • Child the parent:
      • There is no $emit method like Vue
      • Define the relevant data manipulation method (or other callback) in the parent, pass the method to the child, and call the parent in the child to pass the message
    • Brother and younger brother:
      • Host the data to the parent and then pass it to the children
  • We can see simple component communication through just one props, which is really simple and saves us a lot of API memorization
  • Note: In react. js, data flows from top to bottom. That is, a parent component can pass its state/props to its children, but the children cannot change the functions-react. js is a one-way data flow. If a child component needs to modify the parent component’s state (data), it does so through a callback function
  • In the following example, Child is a Child of App
  • App
class App extends Component {
    state = {
        name: 'milk'
    }
    setName = newName= > {
        this.setState({
            name: newName
        })
    }
    render() {
        let { name } = this.state;
        return (
            <div>
                <Child name={name} setName={this.setName}></Child>
            </div>)}}Copy the code
  • Child
export default class Child extends Component {
    state = {
        count: 1
    }
    render() {
        let { count } = this.state;
        let { name, setName } = this.props;
        return (
            <div>
                <p>name: {name}</p>
                <p>count: {count}</p>
                <button onClick={()= >{this.setState({count: count + 1})}}> incremented</button>
                <button onClick={()= >{setName(' milk ')}}> Chinese name</button>
            </div>)}}Copy the code

Communicate context across components

  • Imagine a scenario, again, with a structure: parent -> child -> grandchild. How do we convey information in this scenario?
  • Sure, the first thing that comes to mind is props. That’s easy. Just pass it along, pass it along
  • Example: App -> Child -> SubChild
  • App
class App extends Component {
    state = {
        name: 'milk'
    }
    setName = newName= > {
        this.setState({
            name: newName
        })
    }
    render() {
        let { name } = this.state;
        return <Child name={name} setName={this.setName}></Child>}}Copy the code
  • Child
class Child extends Component {
    render() {
        // The direct structure props is passed down
        return <SubChild {. this.props} ></SubChild>}}Copy the code
  • SubChild
class SubChild extends Component {
    render() {
        let { name, setName } = this.props;
        return (<div>
            <p>name: {name}</p>
            <button onClick={()= >{setName(' milk ')}}> Chinese name</button>
        </div>)}}Copy the code
  • If it’s just the case up here it’s fine, but if it’sAnd the posterity is endlessHow to do a lot of descendants? It is impossible to pass them all on. It is troublesome and difficult to find the source
  • So what do we do? Those familiar with Vue may have thought of itprovideinjectReact has a similar method – content
  • React.createContent– Creates a container for the context
  • Provider– Producer, a place that produces shared data and places shared data in value
  • Consumer– Consumers, which specialize in consuming data produced by producers, need to be nested under producers. To retrieve the shared data source through a callback
  • Example: App -> Child -> SubChild
import { createContext } from 'react'

const content = createContext();
const { Provider, Consumer } = content;

export { Provider, Consumer };
export default content;
Copy the code
  • App
import { Provider } from './content'
class App extends Component {
    state = {
        name: 'milk'
    }
    setName = newName= > {
        this.setState({
            name: newName
        })
    }
    render() {
        let { name } = this.state;
        return (
            <div>
                <Provider value={{
                    name: name.setName: this.setName}} >
                    <Child></Child>
                </Provider>
            </div>)}}Copy the code
  • SubChild
Use 
      
        to wrap the part of the data required by the callback
      
class SubChild extends Component {
    render() {
        let { count } = this.state;
        return (
            <Consumer>
                {(content) => {
                    console.log(content);
                    return (<div>
                        <p>name: {content.name}</p>
                        <button onClick={()= >{content.setName(' milk ')}}> Chinese name</button>
                    </div>)}}</Consumer>)}}Copy the code
  • Look, isn’t it convenient, you don’t have to pass it down layer by layer, but there are some problems.<Consumer>Too troublesome, where to use the data need to write so many things, this nesting I also look very uncomfortable, not good
  • We can also use method two to bind the content to the class private contextType property, and then we can access the data through this.context
/ / method 2
class SubChild extends Component {
    / / binding 1
    static contextType = content;
    render() {
        let { name, setName } = this.context;
        return (<div>
            <p>name: {name}</p>
            <button onClick={()= >{setName(' milk ')}}> Chinese name</button>
        </div>)}}2 / / binding
// SubChild.contextType = content;
Copy the code
  • Mainly with VueprovideinjectAgain, recommendations are not used in projects, but are generally used when encapsulating advanced components

Component life cycle

  • The so-called life cycle refers to the various stages of a thing from the beginning to the end. Of course, in react. js, it refers to the process of component creation and destruction. Functions called by react. js at different stages of this process can be used to control components more accurately. The render function we’ve been using up until now is actually a function executed during the render phase of the component’s life cycle
  • The React component life cycle is divided into three phases: mount, update, and uninstall

Mount the stage

  • Mount – Component create -> component create virtual DOM -> generate, mount to the real DOM
  1. constructor(props)– Initializes components
  2. static getDerivedStateFromProps(props)– Associate some data in props to the state state
  3. render()– Call the render method to generate the virtual DOM
  4. componentDidMount– Components are mounted successfully
class Child extends Component {
    constructor(props) {
        console.log(0.'Initialize component');
        super(props);
        this.state = {
            count: 1}}// Associate some data in props to the state
    static getDerivedStateFromProps(props) {
        // Add the corresponding data to state
        console.log(1.'Associate props to state');
        return {
            name: props.name
        }
    }
    // The component is mounted. If you want to get the real DOM, get it in this method
    componentDidMount() {
        console.log(3.'Component mount complete');
        console.log(document.querySelector('#name'));
    }
    render() {
        console.log(2.Call render and generate the virtual DOM based on render's return value.);
        let { name, count } = this.state;
        let { setName } = this.props;
        return (
            <div>
                <p id="name">name: {name}</p>
                <p>count: {count}</p>
                <button onClick={()= >{this.setState({count: count + 1})}}> incremented</button>
                <button onClick={()= >{setName(' milk ')}}> Chinese name</button>
            </div>)}}Copy the code

Update the stage

  1. static getDerivedStateFromProps(props)– Associate some data in props to the state state
  2. shouldComponentUpdate(nextProps, nextState)– Controls whether components are updated
    • NextProps – Updated props
    • This. Props – Updates the props before
    • NextState – Updated state
    • This.state – The state before the update
    • Return value: true to continue the update process with component updates, false to interrupt the update process with no further updates
  3. render()– Call the render method to generate the virtual DOM
  4. getSnapshotBeforeUpdate(prevProps, prevState)– Gets and returns a pre-update DOM snapshot
  5. componentDidUpdate(prevProps, prevState, prevDOM)– Component update completed
    • prevDOM – getSnapshotBeforeUpdateThe return value
class Child extends Component {
    state = {
        count: 1
    }
    // Associate some data in props to the state
    static getDerivedStateFromProps(props) {
        // Add the corresponding data to state
        console.log(0.'Associate props to state');
        return {
            name: props.name
        }
    }
    // Controls whether the component is updated
    shouldComponentUpdate(nextProps, nextState) {
        console.log(1.'Control whether components are updated');
        // nextProps - Props after update
        // this. Props - Update the props before

        // nextState - The updated state
        // this.state - The state before the update

        return true // False interrupts the update process and does not continue the update
    }
    // Get a pre-update DOM snapshot
    getSnapshotBeforeUpdate(prevProps, prevState) {
        In this step, the component is about to update the view (the real DOM), and we can get the state of the DOM tree before the update
        console.log(3.'Get and return a pre-update DOM snapshot');
        let count = document.querySelector('#count');
        return count.innerHTML
    }
    // Component update completed
    componentDidUpdate(prevProps, prevState, prevDOM) {
        console.log(4.'Component update completed');
        let count = document.querySelector('#count');
        console.log(prevDOM);
        console.log(count);
    }
    render() {
        console.log(2.Call render and generate the virtual DOM based on render's return value.);
        let { name, count } = this.state;
        let { setName } = this.props;
        return (
            <div>
                <p id="name">name: {name}</p>
                <p id="count">count: {count}</p>
                <button onClick={()= >{this.setState({count: count + 1})}}> incremented</button>
                <button onClick={()= >{setName(' milk ')}}> Chinese name</button>
            </div>)}}Copy the code

Unloading phase

  1. componentWillUnmount– Components are to be uninstalled
    • Generally used to delete some information or operations added globally
class Child extends Component {
    state = {
        size: window.innerWidth
    }
    componentDidMount() {
        window.onresize = () = > {
            this.setState({
                size: window.innerWidth
            })
        };
    }
    // The component will be uninstalled
    componentWillUnmount() {
        console.log(0.'Component about to unload');
        window.onresize = null;
    }
    render() {
        let { size } = this.state;
        return (
            <div>
                <p>size: {size}</p>
            </div>)}}Copy the code

graphic