1, React Hooks introduction

React Hooks are enhancements to functional components that can store state, have the ability to handle side effects, and allow developers to implement the same functionality without using class components.

Class component deficiencies (issues to be addressed by Hooks)

  1. Lack of logical reuse mechanism

In order to reuse the logic to increase the actual rendering effect of the component, the component hierarchy display is very bloated, increasing the difficulty of debugging and reduce the efficiency of operation

  1. Class components can often become too complex to maintain

Split a set of coherent business logic into multiple lifecycle functions Where there are multiple unrelated business logic within a lifecycle function

  1. The class member methods do not guarantee the correctness of the this pointer

React Hooks

React Hooks are a set of hook functions that enhance functional components. React Hooks provide different functions

seState()

useEffect()

useReducer()

useRef()

useCallback()

useContext()

useMemo()

useState()

Use useState to let functional components hold state

import React, { useState } from 'react';

function App() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  )
}

export default App
Copy the code

UseState usage details


1. Accept a unique parameter, the initial value of the status. The initial value can be any data type

2. Return an array. Array to store state values and methods to change state values. The method name convention begins with set followed by the state name

3. Methods can be called multiple times. Used to store different state values

4. The argument can be a function, and the initial state is what the function returns, and the function is called only once, when the initial value is a dynamic value

import React, { useState } from 'react'; Function App (props) {/ / every time rendering is pointless use useState parameters initialization data for the function of writing / / const propsCount = props. Count | | 0 const [count, SetCount] = useState (() = > {return props. Count | | 0}) const [person, setPerson] = useState ({name: "zhang", the age: 22}) return ( <div> <span>{count} {person.name} {person.age} {person.sex}</span> <button onClick={() => setCount(count + <button onClick={() => setPerson({name:" name ", age: "name ", age:" name "); 30})}>setLisi</button> {/* <button onClick={() => setPerson({... Person, name: ""})}>setWangwu</button> </div>)} export default AppCopy the code

Sets the details of the use of the status value method


The parameter to the set status method can be either a value or a function

The method that sets the status-value method is itself asynchronous

import React, { useState } from 'react'; function App() { const [count, SetCount] = useState(0) function handleCount() {setCount(count => {document.title =) count; //return count + 1 const newCount = count + 1; document.title = newCount; return newCount; // document.title = count} return (<div> <span>{count}< span> <button onClick={handleCount}>+1</button> </div> ) } export default AppCopy the code

useReducer()

UseReducer is another way to keep the state of function components

import React, { useReducer } from 'react';

function App() {
  function reducer(state, action) {
    switch(action.type) {
      case "increment":
        return state + 1
      case "decrement":
        return state - 1
      default:
        return state
    }
  }

  const [count, dispatch] = useReducer(reducer, 0)
  
  return (
    <div>
      <button onClick={() => dispatch({type: "increment"})}>+1</button>
      <span>{count}</span>
      <button onClick={() => dispatch({type: "decrement"})}>-1</button>
    </div>
  )
}

export default App
Copy the code

useContext()

Simplify code for retrieving data when retrieving data across component hierarchies

import React, { createContext, useContext } from 'react'; const countCotext = createContext() function App() { return ( <countCotext.Provider value={100}> <Foo /> </ countcotext.provider >)} function Foo() {const value = useContext(countCotext) return <div> I am Foo component {value}</div> // consume the data provided by the Provider // return (// < countcotext.consumer > // {// value => {// return <div>{value}</div> // } // } // </countCotext.Consumer> // ) } export default AppCopy the code

useEffect()

Give functional components the ability to handle side effects, similar to life cycle functions

UseEffect can be viewed as a combination of componentDidMount, componentDidUpdate, and componentWilUnmount

import React, { useState, useEffect } from 'react'; import ReactDOM from 'react-dom' function App() { const [count, SetCount] = useState(0) // useEffect(() => {// console.log(333) // execute // after the component is mounted useEffect(() => { // console.log(333) // }, UseEffect (() => {return () => {console.log(" Component uninstalled ")}}) return (<div> <span>{count}</span> <button  onClick={() => setCount(count + 1)}>+1</button> <button onClick={() => ReactDOM.unmountComponentAtNode( Document.getelementbyid ('root'))}> Uninstall component </button> </div>)} export default AppCopy the code

UseEffect is the second parameter

import React, { useState, useEffect } from 'react'; function App() { const [count, setCount] = useState(0) const [person, setPerson] = useState({name: UseEffect useEffect(() => {document.title = count console.log("count")}, [count]) return ( <div> <span>{count} {person.name}</span> <button onClick={() => setCount(count + 1)}>+1</button> <button onClick={() => setPerson({name: "button "})}>setPerson</button> </div>)} export default AppCopy the code

UseEffect combines asynchronous functions


The argument function in useEffect cannot be an asynchronous function because useEffect returns a function that cleans up the resource. If it is an asynchronous function, it returns a Promise

import React, { useEffect } from 'react'; function App() { useEffect(() => { // getData().then(data => console.log(data)) (async function() { const data = await getData() console.log(data) })() }, []) function getData() { return new Promise((resolve, Reject = > {setTimeout () () = > {resolve (" data, data..." ) }, 500) }) } return <div></div> } export default AppCopy the code

useMemo()

UseMemo behaves like calculated properties in Vue and can monitor changes in a value and calculate new values based on the changes

UseMemo caches the calculated results if the monitored values have not changed; Even if the component is re-rendered, it is not recalculated, and this behavior can help avoid expensive calculations on each render

import React, { useState, useMemo } from 'react'; function App() { const [count, setCount] = useState(0) const [bool, SetBool] = useState(true) const result = useMemo(() => {console.log("useMemo function executed ") return count * 2}, [count]) return ( <div> <span>{count} {result}</span> <span>{bool ? "True" : "false"} < / span > < button onClick = {() = > setCount (count + 1)} > + 1 < / button > < button onClick = {() = > setBool (! bool)}>setBool</button> </div> ) } export default AppCopy the code

Memo method

Performance optimization to prevent component updates if the data in the component has not changed. Similar to PureComponent and shouldComponentUpdate in class components

import React, { useState, memo } from 'react'; function App() { const [count, setCount] = useState(0) return ( <div> <span>{count}</span> <button onClick={() => setCount(count + 1)}>+1</button> <Foo // function Foo() {// console.log("Foo was rerendered "); // function Foo() {// console.log("Foo was rerendered "); // return <div>Foo component </div> //} // Use memo const Foo = memo(() => {console.log("Foo component was rerendered ") return <div>Foo component </div>})  export default AppCopy the code

useCallback()

Performance optimization, caching functions so that components get the same function instance when re-rendering

import React, { useState, memo, useCallback } from 'react'; function App() { const [count, setCount] = useState(0) const resetCount = useCallback(() => { setCount(0) }, // const resetCount = () => {// setCount(0) => {// setCount(0) // return ( <div> <span>{count}</span> <button onClick={() => setCount(count + 1)}>+1</button> <Foo resetCount={resetCount}/> </div> )} const Foo = memo((props) => {console.log("Foo was rerendered ") return (<div> <div>Foo </div> <button onClick={props.resetCount}>resetCount</button> </div> ) }) export default AppCopy the code

useRef()

Gets the DOM element object

import React, { useRef } from 'react'; function App() { const container = useRef() return ( <div ref={container}> <button onClick={() => Console. log(container)}> Get container</button> </div>)} export default AppCopy the code

Save data (across component cycles)

Even if the component is re-rendered, the saved data is still there, and changes to the saved data do not trigger the component to re-render

import React, { useState, useEffect, useRef } from 'react'; function App() { const [count, setCount] = useState(0) let timerId = useRef(); useEffect(() => { timerId.current = setInterval(() => { setCount(count => count + 1) }, 1000) }, []) const stopCount = () => { console.log(timerId); ClearInterval (timerid.current)} return (<div> <span>{count}</span> <button onClick={stopCount}> stop </button> </div>)} export default AppCopy the code

Customize the Hook

Custom hooks are a standard way to encapsulate and share logic

A custom Hook is a function whose name begins with use

Custom hooks are a combination of logic and built-in hooks

A,

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

function App() {
  const [post, setPost] = useState({})

  useEffect(() => {
    axios.get("https://www.fastmock.site/mock/13089f924ad68903046c5a61371475c4/api/post").then(
      res => setPost(res.data)
    )
  }, [])
  
  return (
    <div>
      <div>{post.title}</div>
      <div>{post.body}</div>
    </div>
  )
}

export default App
Copy the code

Use custom Hook encapsulation

import React, { useState, useEffect } from 'react'; import axios from 'axios' function useGetPost() { const [post, setPost] = useState({}) useEffect(() => { axios.get("https://www.fastmock.site/mock/13089f924ad68903046c5a61371475c4/api/post").then( res => setPost(res.data) ) }, []) return [post, setPost] } function App() { const [post, setPost] = useGetPost() return ( <div> <div>{post.title}</div> <div>{post.body}</div> <button onClick={() => SetPost ({title:"zhangsan", body:123})}> Set article </button> </div>)} export default AppCopy the code

Second,

import React, { useState } from 'react'; function useUpdateInput(initialValue) { const [value, setValue] = useState(initialValue) return { value, onChange: event => setValue(event.target.value) } } function App() { const usernameInput = useUpdateInput(""); const passwordInput = useUpdateInput(""); const submitForm = event => { event.preventDefault(); console.log(usernameInput.value) console.log(passwordInput.value) } return ( <form onSubmit={submitForm}> <input type="text" name="username" {... usernameInput}/> <input type="password" name="password" {... passwordInput}/> <input type="submit" /> </form> ) } export default AppCopy the code

The React routing Hooks

The react-router-dom route provides the hook function

Implementation principle of useState

import React from "react"; import ReactDOM from "react-dom"; let state = [] let setters = [] let stateIndex = 0 function createSetter(index) { return function (newState) { state[index] = newState render() } } function useState(initialState) { state[stateIndex] = state[stateIndex] ? state[stateIndex] : initialState setters.push(createSetter(stateIndex)) let value = state[stateIndex] let setter = setters[stateIndex] stateIndex++ return [value, setter] } function render() { stateIndex = 0 ReactDOM.render(<App />, document.getElementById("root")) } function App() { const [count, setCount] = useState(0) const [name, Return (<div> <span>{count}</span> <button onClick={() => setCount(count +) 1)} > setCount < / button > < span > {name} < / span > < button onClick = {() = > elegantly-named setName (" li si ")} > elegantly-named setName < / button > < / div >). } export default App;Copy the code

UseEffect implementation principle

import React from 'react'; import ReactDOM from 'react-dom'; function render () { effectIndex = 0; ReactDOM.render(<App />, document.getElementById('root')); } // Let prevDepsAry = []; let effectIndex = 0; Function useEffect (callback, depsAry) {/ / figure out whether the callback function if (Object. The prototype. ToString. Call (the callback)! == '[object Function]') throw new Error('useEffect '); If (typeof depsAry === 'undefined') {if (typeof depsAry === 'undefined') {return (); If} else {/ / figure out whether depsAry array (Object. The prototype. ToString. Call (depsAry)! == '[object Array]') throw new Error('useEffect must be an Array '); PrevDeps = prevDepsAry[effectIndex]; Callback let hasChanged = prevDeps? depsAry.every((dep, index) => dep === prevDeps[index]) === false : true; If (hasChanged) {callback(); } prevDepsAry[effectIndex] = depsAry; effectIndex++; } } function useReducer (reducer, initialState) { const [state, setState] = useState(initialState); function dispatch (action) { const newState = reducer(state, action); setState(newState); } return [state, dispatch]; } function App() { function reducer (state, action) { switch (action.type) { case 'increment': return state + 1; case 'decrement': return state - 1; default: return state; } } const [count, dispatch] = useReducer(reducer, 0); return <div> {count} <button onClick={() => dispatch({type: 'increment'})}>+1</button> <button onClick={() => dispatch({type: 'decrement'})}>-1</button> </div>; } export default App;Copy the code

Implementation principle of useReducer

import React from 'react';
import ReactDOM from 'react-dom';

function useReducer (reducer, initialState) {
  const [state, setState] = useState(initialState);
  function dispatch (action) {
    const newState = reducer(state, action);
    setState(newState);
  }
  return [state, dispatch];
}

function App() {
  function reducer (state, action) {
    switch (action.type) {
      case 'increment':
        return state + 1;
      case 'decrement':
        return state - 1;
      default:
        return state;
    }
  }
  const [count, dispatch] = useReducer(reducer, 0);
  return <div>
    {count}
    <button onClick={() => dispatch({type: 'increment'})}>+1</button>
    <button onClick={() => dispatch({type: 'decrement'})}>-1</button>
  </div>;
}

export default App;
Copy the code