knowledge

  • Function component
  • Uncontrolled component
  • Portals
  • context
  • Asynchronous components

Function component

  • A pure function, props, JSX
  • No instances, no lifecycle, no state
  • Other methods cannot be extended

Uncontrolled component

  • ref
  • defaultValue defaultChecked
  • Manually manipulate DOM elements

Uncontrolled Components use scenarios:

  • DOM elements must be manipulated manually; setState cannot be implemented
  • File upload<input type=file>
  • Some rich text editors need to pass in DOM elements

Controlled versus uncontrolled components

  • Use controlled components preferentially in accordance with React design principles (data-driven view)
  • Use uncontrolled components when you must manipulate the DOM

Review controlled Components

import React from 'react'

class FormDemo extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            name: 'aa'.info: 'Personal Information'.city: 'beijing'.flag: true.gender: 'male'}}render() {
         // Controlled components
         return <div>
             <p>{this.state.name}</p>
             <label htmlFor="inputName">Name:</label>{/* replace for */} with htmlFor<input id="inputName" value={this.state.name} onChange={this.onInputChange}/>
         </div>

    }
    onInputChange = (e) = > {
        this.setState({
            name: e.target.value
        })
    }
}

export default FormDemo
Copy the code

Uncontrolled component demonstration

import React from 'react'

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            name: 'aa'.flag: true,}this.nameInputRef = React.createRef() / / create the ref
        this.fileInputRef = React.createRef()
    }
    render() {
         // input defaultValue
         return <div>{/* use defaultValue instead of value, use ref */}<input defaultValue={this.state.name} ref={this.nameInputRef}/>{/* state does not change with */}<span>state.name: {this.state.name}</span>
             <br/>
             <button onClick={this.alertName}>alert name</button>
         </div>

         // checkbox defaultChecked
         return <div>
             <input
                 type="checkbox"
                 defaultChecked={this.state.flag}
             />
         </div>

        // file
        return <div>
            <input type="file" ref={this.fileInputRef}/>
            <button onClick={this.alertFile}>alert file</button>
        </div>

    }
    alertName = () = > {
        const elem = this.nameInputRef.current // Get the DOM node from ref
        alert(elem.value) / / not enclosing state. The name
    }
    alertFile = () = > {
        const elem = this.fileInputRef.current // Get the DOM node from ref
        alert(elem.files[0].name)
    }
}

export default App

Copy the code

“Portals”

  • By default, components will be rendered nested within a given hierarchy
  • How do I get a component to render outside of its parent?

Portals Usage Scenario

  • overflow:hidden
  • The z-index value of the parent component is too small
  • Fixed should be placed at the first level of body

index.js

import React from 'react'
import PortalsDemo from './PortalsDemo'

class AdvancedUse extends React.Component {
    constructor(props) {
        super(props)
    }
    render() {
        return <div>
            <PortalsDemo>Content of the Modal</PortalsDemo>
        </div>}}export default AdvancedUse

Copy the code

PortalsDemo.jsx

import React from 'react'
import ReactDOM from 'react-dom'
import './style.css'

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
        }
    }
    render() {
        // // Normal rendering
        // return <div className="modal">
        // {this.props.children} {/* vue slot */}
        // </div>

        // Render to the body using Portals.
        // Put fixed elements on the body for better browser compatibility.
        return ReactDOM.createPortal(
            <div className="modal">{this.props.children}</div>.document.body / / the DOM node)}}export default App

Copy the code

style.css

.modal {
    position: fixed;/ * * /
    width: 300px;
    height: 100px;
    top: 100px;
    left: 50%;
    margin-left: -150px;
    background-color: # 000;
    /* opacity: .2; * /
    color: #fff;
    text-align: center;
}
Copy the code

The context

  • How is common information (language, topic) passed to each component?
  • Props is too complicated
  • Make a mountain out of a teacup with redux
import React from 'react'

// Create Context and fill in the default value (any js variable)
const ThemeContext = React.createContext('light')

// Underlying component - Functions are components
function ThemeLink (props) {
    // const theme = this.context Functional components have no instances, i.e. no this

    // Functional components can use Consumer
    return <ThemeContext.Consumer>
        { value => <p>link's theme is {value}</p> }
    </ThemeContext.Consumer>
}

// Underlying component - class component
class ThemedButton extends React.Component {
    // contextType reads the current theme context.
    // Static contextType = ThemeContext // ThemedButton.contextType = ThemeContext
    render() {
        const theme = this.context // React will look up to the nearest theme Provider and use its value.
        return <div>
            <p>button's theme is {theme}</p>
        </div>
    }
}
ThemedButton.contextType = ThemeContext // contextType reads the current theme context.

// The middle component no longer has to specify to pass theme down.
function Toolbar(props) {
    return (
        <div>
            <ThemedButton />
            <ThemeLink />
        </div>)}class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            theme: 'light'}}render() {
        return <ThemeContext.Provider value={this.state.theme}>
            <Toolbar />
            <hr/>
            <button onClick={this.changeTheme}>change theme</button>
        </ThemeContext.Provider>
    }
    changeTheme = () = > {
        this.setState({
            theme: this.state.theme === 'light' ? 'dark' : 'light'}}})export default App

Copy the code

Load components asynchronously (lazy loading)

  • import()
  • React.lazy
  • React.Suspense
import React from 'react'

const ContextDemo = React.lazy(() = > import('./ContextDemo'))

class App extends React.Component {
    constructor(props) {
        super(props)
    }
    render() {
        return <div>
            <p>Introduce a dynamic component</p>
            <hr />
            <React.Suspense fallback={<div>Loading...</div>} ><ContextDemo/>
            </React.Suspense>
        </div>

        // 1. Loading (loading)
        // 2. Look at the js loading of network}}export default App

Copy the code