useEffect

  • UseEffect defaults to the DidMount and Didupdate life cycles
  • UseEffect If the second parameter is set to [], useEffect is executed only once by default, equivalent to DidMount
  • The Didupdate life cycle can be simulated by setting the values to listen for changes in the array of the second parameter
  • Return should function, the content of the function is equivalent to WillUnMount life cycle, in which to execute some, clear timer, clear custom

Note that useEffect emulates both DidMount and Didupdate when the second parameter is not set

  • When the value of the page changes, an update is triggered, and the content of the function returned WillUnMount. In this case, the value retrieved is the same as the last value because of the nature of the closure
const TestFn = () = > {
    const [age, setAge] = useState(22)

    useEffect(() = > {
        console.log('execution useEffect', age)
        return () = > {
            console.log('Simulated component Destruction', age)
        }
    })

    const handleClick = () = > {
        setAge(age+3)}return (
        <Fragment>
            <div>{age}</div>
            <button onClick={handleClick}>Click on the</button>
        </Fragment>)}export default TestFn
Copy the code

memo, useMemo, useCallback

  • It is mainly used for performance optimization
  • When the value of the parent component changes, the child component is also re-rendered, resulting in unnecessary performance waste
  • Operation method, used by subcomponentsmemoThe function wrap returns, and the parent listens for any value changes to the child before rendering the child
  • There’s a function to pass inuseCallback, pass the value, useuseMemoThe second argument to useCallback is an empty array by default
  • useCallbackThe parent component passes the function past to the child component. By default, the function past is passeduseMemoAnd the Memo subcomponents will still be re-rendered, so useuseCallbackTo keep the child components from rerendering,
  • The memo defaults to shallow comparisons, so when the parent component passes a reference type (object, array) to the child component, the child component will still be rerendered, so useuseMemoThe second parameter determines which values change before re-rendering
// The default is shallow comparisons like react. # PureComponent
import React, { useState, memo, useMemo, useCallback } from 'react'

const Child = memo(({userInfo}) = > {
    console.log(99)
    return (
        <div>
            Child
            {userInfo.age}
        </div>)})const TestUseMemo = () = > {
    const [count, setCount] = useState(0)
    const [age, setAge] = useState(1)

    const onClick = () = > {
        setCount(count + 1)}const changeChildVal = () = > {
        setAge(age + 1)}const handleClick = useCallback(() = > {
        console.log('handleClick')}, [])const userInfo = useMemo(() = > {
        return {
            age, 
            city: 'chengdu'
        }
    }, [age])


    return (
        <div>
            <div>{count}</div>
            <div>{age}</div>
            <button onClick={onClick}>Click on the</button>
            <button onClick={changeChildVal}>Click on the 2</button>
            <Child handleClick={handleClick} userInfo={userInfo} />
        </div>)}export default TestUseMemo
Copy the code

Hooks usage specification

  • Use only in react function components and custom hooks, not elsewhere
  • It can only be used for top-level code, not for loop, judgment
  • eslint-plugin-react-hooks

slot

The default slot

<MainFn testMainClick={testMainClick} >
    <div>I'm the default slot</div>
</MainFn>
/ / use
const MainFn = ({children, testMainClick}) = > {
  const handleMain = () = > {
    testMainClick('AAA')}return (
    <div>
      <button onClick={handleMain}>MainFn</button>
      <div>{children // Render children directly to the default slot, default is a JSX, code snippet}</div>
    </div>)}Copy the code

Named slot, and scope slot

  • A named slot is equivalent to passing in an object, and the key of the object is equivalent to the name of the slot
  • The scope slot is also passing in an object, each of which corresponds to the value of the key, and passing in a function. The reason for passing in a function is to pass the argument back to the function where the child component uses the slot
  • JSX and React are written the same in VUe3, except when slots are used for child components
  • The default slot is ctx.slots.default(). The default slot for react is props. Children
  • Vue3 gets the named slot and the scope slot ctx.slot.slot1 (666),react :props.children.slot1()
//react
const TestChild = () = > {
  const testMainClick = (val) = > {
    console.log('Get the value passed by the child component', val)
  }

  return (
    <div>
      TestChild
      <MainFn testMainClick={testMainClick} >
        {
          {
            test1(val) {
              console.log('slotAAA', val)
              return <>
                <div>test1__slot</div>
                <div>{val}</div>
              </>}}}</MainFn>
    </div>
  )
}
/ / child component
const MainFn = ({children, testMainClick}) = > {
  const { test1 } = children

  console.log('children', children)

  const handleMain = () = > {
    testMainClick('AAA')}return (
    <div>
      <button onClick={handleMain}>MainFn</button>
      <div>{test1(' pass value back ')}</div>
    </div>)}Copy the code

The use of slots in VUE3

/* Function components with React mode in VUe3 are not responsive */
const TestChild = (props) = > {
  console.log('props', props)
  const data = reactive({ city: 'chongqing' })

  const handleChild = () = > {
    data.city = 'chengdu'
    console.log('handleChild', data)
  }

  return (
    <div>
      <div>{data.city}</div>
      <div>TestChild</div>
      <button onClick={handleChild}>change</button>
    </div>)}/* Functional components in the setup format are reactive */
const TestChild2 = {
  props: {
    city: String
  },
  setup(props, ctx) {
    console.log('propssetup', props, ctx)
    const data = reactive({ city: 'Beijing' })

    const handleChild = () = > {
      data.city = 'Shanghai'
      console.log('handleChild', data)
    }

    return () = > {
      return (
        <div>
          <div>{data.city}</div>
          <div>TestChild2</div>
          <button onClick={handleChild}>change</button>
          <div>{ctx.slots.default(22)}</div>
          <div>{ctx.slots.slot1(666)}</div>
        </div>)}}}// The vuejsx neutron component wants to pass parameters to the parent component, via props.fn()
// If the template method is used, you need to define emits
/ / way
<TestChild
name="AA"
    v-slots={{
        default(val) {
            return <div>TestChildAAA{val}</div>
        },
        slot1(val) {
            return <div>TestChildAAA{val}</div>}}} >2 / / way
<TestChild>
  {{
      default(val) {
            return <div>TestChildAAA{val}</div>
        },
        slot1(val) {
            return <div>TestChildAAA{val}</div>}}}</TestChild>
Copy the code

react-dom

  • createPortalthroughcreatePortalThe implementation inserts elements into nodes and performs better than the native method
import ReactDOM from 'react-dom'
ReactDOM.createPortal(
    <div className="modal">{this.props.children}</div>.document.body / / the DOM node
)
Copy the code

prop-types

  • prop-typesImplement type checking for props
import PropTypes from 'prop-types'

Copy the code

syntheticEvent

  • React events are events that react encapsulates.
  • React16 event bound to document
  • The REact17 event is bound to the root component, which makes it easier to have multiple React components, such as a micro front end

The controlled components

  • It is equivalent to bidirectional data binding
  • The value in the input is changed by data
  • OnChange to control input

Uncontrolled component

    <input defaultValue={this.state.name} ref={this.inputRef} />
    
Copy the code
  • When uploading files, you must use uncontrolled components

setState

  • Immutable values, when do you modify them, when do you append them, not in advance
  • It may be an asynchronous update
  • It may be merged
  • Although methods like array push can still render successfully, their values are the same throughout the shouldeComponentUpdate lifecycle, so comparisons can’t be judged
    //nextProps, modified props
    // Change the current state value
    // Compare this.state with nextState and props with nextProps
    // Return true if you want to rerender, false otherwise
    shouldComponentUpdate(nextProps, nextState) {
        console.log('nextProps'.this.state)
        console.log('shouldComponentUpdate', nextProps, nextState)
        return true
    }
    this.inputRef = createRef()
    <input type='file' ref={this.inputRef} />
    console.log('ref'.this.inputRef.current.files)
Copy the code

immutable

  • New data structures are generally implemented through the IMmutable library, rather than using depth comparisons, object

The original HTML

const rawHtml = ' Rich text content < I > italic 
        bold '
const rawHtmlData = {
    __html: rawHtml // Note that it must be in this format
}
const rawHtmlElem = <div>
    <p dangerouslySetInnerHTML={rawHtmlData}></p>
    <p>{rawHtml}</p>
</div>
return rawHtmlElem
Copy the code

Equivalent to nextTick of VUE

const useSyncCallback = callback= > {
    const [proxyState, setProxyState] = useState({ current: false })

    useEffect(() = > {
        if (proxyState.current === true) setProxyState({ current: false })
    }, [proxyState])

    useEffect(() = > {
        proxyState.current && callback()
    })

    return useCallback(() = > {
        setProxyState({ current: true })
    }, [proxyState])
}
const onClick = () = > {
    setCount(count + 1)
    nextTick()  // Get the latest data after execution
}
const nextTick = useSyncCallback(() = > {
    console.log('After change', count)
})
Copy the code

HOC high-level components

import React from 'react'

// Higher-order components
const withMouse = (Component) = > {
    class withMouseComponent extends React.Component {
        constructor(props) {
            super(props)
            this.state = { x: 0.y: 0 }
        }
  
        handleMouseMove = (event) = > {
            this.setState({
                x: event.clientX,
                y: event.clientY
            })
        }
  
        render() {
            return (
                <div style={{ height: '500px'}}onMouseMove={this.handleMouseMove}>{/* 1. Pass through all props 2.<Component {. this.props} mouse={this.state}/>
                </div>)}}return withMouseComponent
}

const App = (props) = > {
    const a = props.a
    const { x, y } = props.mouse // Receive mouse attributes
    return (
        <div style={{ height: '500px' }}>
            <h1>The mouse position is ({x}, {y})</h1>
            <p>{a}</p>
        </div>)}export default withMouse(App) // Return the higher-order function
Copy the code

renderProps

import React from 'react'
import PropTypes from 'prop-types'

class Mouse extends React.Component {
    constructor(props) {
        super(props)
        this.state = { x: 0.y: 0 }
    }
  
    handleMouseMove = (event) = > {
      this.setState({
        x: event.clientX,
        y: event.clientY
      })
    }
  
    render() {
      return (
        <div style={{ height: '500px'}}onMouseMove={this.handleMouseMove}>{/* Pass the current state to render(render is a function component) */} {this.props. Render (this.state)}</div>
      )
    }
}
Mouse.propTypes = {
    render: PropTypes.func.isRequired // You must receive a render attribute, which is a function
}

const App = (props) = > (
    <div style={{ height: '500px' }}>
        <p>{props.a}</p>
        <Mouse render={/ *renderIs a function component */ ({x.y}) = > <h1>The mouse position is ({x}, {y})</h1>} / ></div>
)

/** * that is, the Mouse component is defined with only the ability to get x and y. * As for how Mouse components are rendered, the App tells Mouse through Render Prop. * /

export default App

Copy the code

forwardRef

    // Function components can be passed to ref, or higher order components
    forwardRef((props, ref) = > {})
Copy the code

react-router-dom

// withRouter can be used to get props. Location, props. Match.params
// This can also be done using hooks provided, useParams,useLocation
//BrowserRouter Specifies the h5 route
// HashRouter Hash mode
UseHistory props.history.push(' /article/${res.id} ')
// props.history.push(`/? page=1&keyword=${keyword}`)
<BrowserRouter>
    // Slots can also be used
    <Route path='/testRouter' component={TestRouter}></Route>
    <Route path='/ClassRouter/:age' component={ClassRouter}></Route>
</BrowserRouter>
// Exact matches only when exact matches. In nested routes, two-level routes can be used but one-level routes cannot be used
//NavLink has an active activeClassName
//Route can be rendered in three ways: by slot, by render, by Component
// The general nested routine is to use a slot or render, render can make the subcomponent get props,
<Route path='/Home' render={(props)= >
    <div>// Let home get props<Home {. props} / >
        <Route path='/Home/Child1' exact component={Child1} />
        <Route path='/Home/Child2' exact component={Child2} />
    </div>} >Copy the code

React is based on the concept of immutable values, and Redux is also immutable values

  • Hooks are also mutable values

redux

  • Three packages need to be importedredux.redux-thunk.react-redux

  • reduxProvides some methods to inject store, and middleware load functions
  • react-reduxComponents and methods that are primarily used to get state and Dispatch, and Provide
  • redux-thunkA middleware that handles asynchrony. To handle asynchrony, this middleware must be added

#### Sample code

import * as redux from 'redux'
import thunk from 'redux-thunk'

import * as reactRedux from 'react-redux'
import * as reduxThunk from 'redux-thunk'



console.log('redux', redux)
console.log('reactRedux', reactRedux)
console.log('reduxThunk', reduxThunk)


const { createStore, applyMiddleware } = redux

const defaultState = {
    name: 'Joe'.city: 'chengdu'.age: 22.list: {
        yy: 32}}const promiseFn = (query) = > {
    return new Promise((resolve, reject) = > {
        setTimeout(() = > {
            resolve('Execute in one second' + query)
        }, 1000); })}/* Synchronization */
export const getName = (list) = > {
    // Usually return directly, but in order to get the value in the returned function, use the asynchronous method, which can return a value
    // return {
    // type: 'NAME_ACTION',
    // payload: list
    // }
    return (dispatch) = > {
        dispatch({
            type: 'NAME_ACTION'.payload: list
        })
        return list
    }
}

/* Asynchronous processing */
export const getAsyncName = (list) = > {
    return (dispatch) = > {
        return promiseFn(list).then(res= > {
            dispatch({
                type: 'NAME_ACTION'.payload: res
            })
            return res
        })
    }
}

const reducer = (state = defaultState, action) = > {
    // console.log(' test action', action)
    if(action.type === 'NAME_ACTION') {
        // state.age = action.payloadstate.list.yy = action.payload state = {... state} }return state
}

const store = createStore(reducer, applyMiddleware(thunk))

import React from 'react'
import * as reactRedux from 'react-redux'
import { getName, getAsyncName } from '.. /.. /.. /store/index'


// console.log('; reactRedux', reactRedux, getName)

const { useDispatch, useSelector } = reactRedux



const Child1 = (props) = > {
    const disptch = useDispatch()

    const age = useSelector(state= > {
        // console.log(' get ', state.list.yy)
        // return state.age
        return state.list.yy
    })

    const handleBtn1 = () = > {
        const data = disptch(getName('Synced up, buddy.'))
        console.log('get AAA', data)
    }

    const handleBtn2 = () = > {
        disptch(getAsyncName(883263)).then(res= > {
            console.log('res', res)
        })
        // console.log(' get AAA', age)
    }

    console.log('the Child1 props', props)
    return <div>
        Child1
        <div>AA{age}</div>
        <button onClick={handleBtn1}>Synchronously triggers redux</button>
        <button onClick={handleBtn2}>Asynchronously trigger redux</button>
    </div>
}

export default Child1

export default store

// Inject at the top-level store
<Provider store={store}>
    <App />
</Provider>
Copy the code

React Install the TS environment

npx create-react-app my-react-ts –typescript

React uses typescript

import React from "react";

interfacetestProps { message? :string
}
// You can use the react. FC abbreviation
const Test: React.FunctionComponent<testProps> = (props) = > {
    return <div>
        {props.message}
    </div>
}

Test.defaultProps = {
    message: 'Hello.'
}

export default Test

Copy the code

React dynamically adds classes

  • The installationnpm i classnames