React learning the twelfth day React Hooks parses the features after react16.8

Table of contents:

1 Know and experience Hooks

2 State/Effect

3 Context/Reducer

4 Callback/Memo

5 Ref/LayoutEffect

6 Custom Hooks use

After that, you can use hooks to develop more, but you still need to know how to use class components

1. Know and experience Hooks

Functions are the defect of components:

1. Changing the variables in the function component will not trigger render to re-render

2. The conditions that can trigger re-rendering, because there is no place to save the new variable value, the final rendered variable value is still the default value

3. There is no life cycle

 Disadvantages of class components:

(1) When the logic is complex, the code is bloated

(2) The class itself is complex, what does this point to

(3) You need to use higher-order functions to realize the use of some things

 Using hooks can simplify the amount of code, look concise, and no longer have this pointing problems

Hooks must be used at the top level of the function, otherwise an error will be reported

correct:

Error:

Hooks cannot be used in class components, nor can hooks be used in other ordinary functions. But hooks can be used in custom hooks.

Ordinary functions using hooks will report an error:

It is allowed to use other hooks in custom hooks:

 

 

 

 

2. State/Effect

1. const [The first parameter is the return value, the second parameter is the original function to reset the stored value] = useState (initial value) must have a value in the brackets, otherwise the initial value is undefined

The first parameter is similar to this.state; the second parameter is similar to setState

(1) When the function is called, it will be destroyed, and the variable inside is gone. useState is equivalent to saving this variable in another function of react, and then taking it out and reusing it, and calling the function to modify the variable value is equivalent to When calling the function that holds the variable

2. Side effects mean some additional functions that can be used after the page rendering is completed, such as network requests, life cycle, dom operations, etc.

(1) useEffect (side effects need to be placed in a separate place):

The following side effects are not placed in a separate place:

The following side effects are placed in separate places:

(2) Clear some listening events in side effects (clearing mechanism)

Note that the code in useEffect will be executed once every time the data is updated, and (4) will talk about how to make the code of useEffect only execute once.

 The way to cancel the monitoring is to write a return function

(3) Multiple useEffects can be used in a component to place different codes respectively

(4) UseEffect performance optimization, control callback execution, so that some things are only executed once or changed by someone.

If you need to control the execution of a certain code because of what changes, write an array in the second parameter of useEffect, and write who is affected by it in the array:

You only need to write an empty array [] in the second parameter of useEffect to execute it only once when the component is loaded, and no matter who changes in the future, the function wrapped by useEffect will not be executed:

 

 

 

 

三、Context/Reducer

Subsequent hooks tend to be used in special scenarios, and the above useState and useEffect are the basics that must be returned.

1. The use of useContext:

(1) Create a context folder and index.js file:

(2) The index.js file corresponding to App.jsx provides data:

(3) Use the provided parameters in the wrapped App.jsx:

2, useReducer (understand)

Equivalent replacement for useState

The scenario of using useReducer is as shown in the figure below. Multiple parameters can be managed at one time, but the code for modifying parameters must be placed in the reducer, which is not easy to operate:

 How to use useReducer:

import React, { memo, useReducer } from 'react'
// import { useState } from 'react'

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

// useReducer+Context => redux

const App = memo(() => {
  // const [count, setCount] = useState(0)
  const [state, dispatch] = useReducer(reducer, { counter: 0, friends: [], user: {} })

  // const [counter, setCounter] = useState()
  // const [friends, setFriends] = useState()
  // const [user, setUser] = useState()

  return (
    <div>
      {/* <h2>当前计数: {count}</h2>
      <button onClick={e => setCount(count+1)}>+1</button>
      <button onClick={e => setCount(count-1)}>-1</button>
      <button onClick={e => setCount(count+5)}>+5</button>
      <button onClick={e => setCount(count-5)}>-5</button>
      <button onClick={e => setCount(count+100)}>+100</button> */}

      <h2>当前计数: {state.counter}</h2>
      <button onClick={e => dispatch({type: "increment"})}>+1</button>
      <button onClick={e => dispatch({type: "decrement"})}>-1</button>
      <button onClick={e => dispatch({type: "add_number", num: 5})}>+5</button>
      <button onClick={e => dispatch({type: "sub_number", num: 5})}>-5</button>
      <button onClick={e => dispatch({type: "add_number", num: 100})}>+100</button>
    </div>
  )
})

export default App

 

4. Callback/Memo

Note: If you really don’t understand, you just need to know that when the parent component wants to pass a function to the child component in the future, it needs to be wrapped by useCallback.

1. useCallback is used for performance optimization

(1) Reason analysis: When a function defined in a functional component is called and re-rendered, the function will be redefined, and then the original function will be destroyed.

 The previous function is destroyed

(2) Using useCallback can optimize the code you use each time or the function wrapped by the original callback, but the wrapped function will still be redefined every time the functional component is re-rendered, so it has no effect.

(3) Callback trap:

(4) useCallback is generally used to optimize when the parent component passes functions to the child component, so as to avoid the parent component from letting the child component re-render and execute the function of the child component to reduce performance. The reason is that if there are many functions in the child component, and one of the functions is passed from the parent component, then when the parent component re-renders, the function will be recreated, and the props of the child component will be obtained from the parent component. The function is also re-acquired, the sub-component is re-rendered, and many functions in the sub-component are also re-created. Performance drops.

import React, { memo, useState, useCallback, useRef } from 'react'

// useCallback性能优化的点:
// 1.当需要将一个函数传递给子组件时, 最好使用useCallback进行优化, 将优化之后的函数, 传递给子组件

// props中的属性发生改变时, 组件本身就会被重新渲染
const HYHome = memo(function(props) {
  const { increment } = props
  console.log("HYHome被渲染")
  return (
    <div>
      <button onClick={increment}>increment+1</button>

      {/* 100个子组件 */}
    </div>
  )
})

const App = memo(function() {
  const [count, setCount] = useState(0)
  const [message, setMessage] = useState("hello")

  // 闭包陷阱: useCallback
  // const increment = useCallback(function foo() {
  //   console.log("increment")
  //   setCount(count+1)
  // }, [count])

  // 进一步的优化: 当count发生改变时, 也使用同一个函数(了解)
  // 做法一: 将count依赖移除掉, 缺点: 闭包陷阱
  // 做法二: useRef, 在组件多次渲染时, 返回的是同一个值
  const countRef = useRef()
  countRef.current = count
  const increment = useCallback(function foo() {
    console.log("increment")
    setCount(countRef.current + 1)
  }, [])

  // 普通的函数
  // const increment = () => {
  //   setCount(count+1)
  // }

  return (
    <div>
      <h2>计数: {count}</h2>
      <button onClick={increment}>+1</button>

      <HYHome increment={increment}/>

      <h2>message:{message}</h2>
      <button onClick={e => setMessage(Math.random())}>修改message</button>
    </div>
  )
})


// function foo(name) {
//   function bar() {
//     console.log(name)
//   }
//   return bar
// }

// const bar1 = foo("why")
// bar1() // why
// bar1() // why

// const bar2 = foo("kobe")
// bar2() // kobe

// bar1() // why

export default App

Note: The difference between useCallback and usememo is that the former returns a function, while the latter returns a value.

Simply put, the role of useMemo is to prevent functional components from re-rendering due to a parameter change while other functions repeatedly execute multiple functions and avoid object type parameters passed to sub-components from re-creating objects due to component re-rendering, and sub-components find object changes , child components re-render meaninglessly.

2. usememo is used to optimize individual function components. Some functions change variables and cause the entire component to be re-rendered, and all other functions in the component are re-executed, wasting performance.

import React, { memo, useCallback } from 'react'
import { useMemo, useState } from 'react'


const HelloWorld = memo(function(props) {
  console.log("HelloWorld被渲染~")
  return <h2>Hello World</h2>
})


function calcNumTotal(num) {
  // console.log("calcNumTotal的计算过程被调用~")
  let total = 0
  for (let i = 1; i <= num; i++) {
    total += i
  }
  return total
}

const App = memo(() => {
  const [count, setCount] = useState(0)

  // const result = calcNumTotal(50)

  // 1.不依赖任何的值, 进行计算
  const result = useMemo(() => {
    return calcNumTotal(50)
  }, [])

  // 2.依赖count
  // const result = useMemo(() => {
  //   return calcNumTotal(count*2)
  // }, [count])

  // 3.useMemo和useCallback的对比
  function fn() {}
  // const increment = useCallback(fn, [])
  // const increment2 = useMemo(() => fn, [])


  // 4.使用useMemo对子组件渲染进行优化
  // const info = { name: "why", age: 18 }
  const info = useMemo(() => ({name: "why", age: 18}), [])

  return (
    <div>
      <h2>计算结果: {result}</h2>
      <h2>计数器: {count}</h2>
      <button onClick={e => setCount(count+1)}>+1</button>

      <HelloWorld result={result} info={info} />
    </div>
  )
})

export default App

 

五、Ref/LayoutEffect

1. useRef has two usages:

(1) Binding DOM

(2) Bind value to solve closure trap

import React, { memo, useRef } from 'react'

const App = memo(() => {
  const titleRef = useRef()
  const inputRef = useRef()
  
  function showTitleDom() {
    console.log(titleRef.current)
    inputRef.current.focus()
  }

  return (
    <div>
      <h2 ref={titleRef}>Hello World</h2>
      <input type="text" ref={inputRef} />
      <button onClick={showTitleDom}>查看title的dom</button>
    </div>
  )
})

export default App
import React, { memo, useRef } from 'react'
import { useCallback } from 'react'
import { useState } from 'react'

let obj = null

const App = memo(() => {
  const [count, setCount] = useState(0)
  const nameRef = useRef()
  console.log(obj === nameRef)
  obj = nameRef

  // 通过useRef解决闭包陷阱
  const countRef = useRef()
  countRef.current = count

  const increment = useCallback(() => {
    setCount(countRef.current + 1)
  }, [])

  return (
    <div>
      <h2>Hello World: {count}</h2>
      <button onClick={e => setCount(count+1)}>+1</button>
      <button onClick={increment}>+1</button>
    </div>
  )
})

export default App

2、useImperativeHandle

import React, { memo, useRef, forwardRef, useImperativeHandle } from 'react'

const HelloWorld = memo(forwardRef((props, ref) => {

  const inputRef = useRef()

  // 子组件对父组件传入的ref进行处理
  useImperativeHandle(ref, () => {
    return {
      focus() {
        console.log("focus")
        inputRef.current.focus()
      },
      setValue(value) {
        inputRef.current.value = value
      }
    }
  })

  return <input type="text" ref={inputRef}/>
}))


const App = memo(() => {
  const titleRef = useRef()
  const inputRef = useRef()

  function handleDOM() {
    // console.log(inputRef.current)
    inputRef.current.focus()
    // inputRef.current.value = ""
    inputRef.current.setValue("哈哈哈")
  }

  return (
    <div>
      <h2 ref={titleRef}>哈哈哈</h2>
      <HelloWorld ref={inputRef}/>
      <button onClick={handleDOM}>DOM操作</button>
    </div>
  )
})

export default App

3、useLayoutEffect

(1) The execution time of useLayoutEffect and useEffect is different 

(2) useLayoutEffect can avoid screen flickering in some cases

Execution time:

import React, { memo, useEffect, useLayoutEffect, useState } from 'react'

const App = memo(() => {
  const [count, setCount] = useState(0)
  
  useLayoutEffect(() => {
    console.log("useLayoutEffect")
  })

  useEffect(() => {
    console.log("useEffect")
  })

  console.log("App render")

  return (
    <div>
      <h2>count: {count}</h2>
      <button onClick={e => setCount(count + 1)}>+1</button>
    </div>
  )
})

export default App

Toggle number useEffect:

import React, { memo, useEffect, useLayoutEffect, useState } from 'react'

const App = memo(() => {
  const [count, setCount] = useState(100)

  useEffect(() => {
    console.log("useEffect")
    if (count === 0) {
      setCount(Math.random() + 99)
    }
  })

  console.log("App render")

  return (
    <div>
      <h2>count: {count}</h2>
      <button onClick={e => setCount(0)}>设置为0</button>
    </div>
  )
})

export default App

Toggle numbers -useLayoutEffect:

import React, { memo, useEffect, useLayoutEffect, useState } from 'react'

const App = memo(() => {
  const [count, setCount] = useState(100)

  useLayoutEffect(() => {
    console.log("useLayoutEffect")
    if (count === 0) {
      setCount(Math.random() + 99)
    }
  })

  console.log("App render")

  return (
    <div>
      <h2>count: {count}</h2>
      <button onClick={e => setCount(0)}>设置为0</button>
    </div>
  )
})

export default App

 

6. Use of custom Hooks

 

Guess you like

Origin blog.csdn.net/weixin_56663198/article/details/129269951