Home  >  Article  >  Web Front-end  >  What are the differences between react hook and class?

What are the differences between react hook and class?

青灯夜游
青灯夜游Original
2022-03-22 12:12:228163browse

Differences: 1. Hooks are written more concisely than classes; 2. The business code of hooks is more aggregated than classes; 3. Logic reuse of class components usually uses render props and HOC, while react hooks provide Use custom hooks to reuse logic.

What are the differences between react hook and class?

The operating environment of this tutorial: Windows7 system, react17.0.1 version, Dell G3 computer.

What are the differences between react hooks and class components? Let's compare react hooks and class components and talk about their differences.

Problems solved by react-hooks

  • Function components cannot have their own state. Before hooks, function components were stateless, and the state of the parent component was obtained through props, but hooks provide useState to maintain the internal state of the function component.

  • The life cycle of the component cannot be monitored in function components. useEffect aggregates multiple life cycle functions. The life cycle of

  • class components is more complicated (the changes are big from version 15 to version 16).

  • class component logic is difficult to reuse (HOC, render props).

The benefits of hooks compared to classes (comparison)

1. The writing method is more concise

We use the simplest counter For example:

class component

class ExampleOfClass extends Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 1
    }
  }
  handleClick = () => {
    let { count } = this.state
    this.setState({
      count: count+1
    })
  }
  render() {
    const { count } = this.state
    return (
      dc6dce4a544fdca2df29d5ac0ea9906b
        e388a4556c0f65e1904146cc1a846beeyou click { count }94b3e26ee717c64999d7867364b1b4a3
        58d87a863b0fd08858af212a24752208点击65281c5ac262bf6d81768915a4a77ac0
      16b28748ea4df4d9c2150843fecfba68
    )
  }
}

hooks

function ExampleOfHooks() {
    const [count, setCount] = useState(0)
    const handleClick = () => {
        setCount(count + 1)
    }
    return (
      

you click { count }

) }

You can see that the code using hooks is compared with the class component code More concise and clear.

2. The business code is more aggregated

When using class components, it often happens that a function appears in two life cycle functions. Writing them separately may sometimes cause problems. forget. For example:

let timer = null
componentDidMount() {
    timer = setInterval(() => {
        // ...
    }, 1000)
}
// ...
componentWillUnmount() {
    if (timer) clearInterval(timer)
}

Since adding a timer and clearing a timer are in two different life cycle functions, there may be a lot of other business code in between, so you may forget to clear the timer if the component is uninstalled. Failure to add a clear timer function may cause problems such as memory leaks and constant network requests.

But using hooks can make the code more centralized, convenient for us to manage, and not easy to forget:

useEffect(() => {
    let timer = setInterval(() => {
        // ...
    }, 1000)
    return () => {
        if (timer) clearInterval(timer)
    }
}, [//...])

3. Convenient logic reuse

Logic reuse of class components usually uses render props and HOC. React hooks provides custom hooks to reuse logic.

The following takes the logic reuse of obtaining the mouse position on the page as an example:

Class component render props method reuse

import React, { Component } from 'react'

class MousePosition extends Component {
  constructor(props) {
    super(props)
    this.state = {
      x: 0,
      y: 0
    }
  }

  handleMouseMove = (e) => {
    const { clientX, clientY } = e
    this.setState({
      x: clientX,
      y: clientY
    })
  }

  componentDidMount() {
    document.addEventListener('mousemove', this.handleMouseMove)
  }

  componentWillUnmount() {
    document.removeEventListener('mousemove', this.handleMouseMove)
  }

  render() {
    const { children } = this.props
    const { x, y } = this.state
    return(
      
{ children({x, y}) }
) } } // 使用 class Index extends Component { constructor(props) { super(props) } render() { return ( { ({x, y}) => { return (

x:{x}, y: {y}

) } }
) } } export default Index

Custom hooks method reuse

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

function usePosition() {
  const [x, setX] = useState(0)
  const [y, setY] = useState(0)

  const handleMouseMove = (e) => {
    const { clientX, clientY } = e
    setX(clientX)
    setY(clientY)
  } 

  useEffect(() => {
    document.addEventListener('mousemove', handleMouseMove)
    return () => {
      document.removeEventListener('mousemove', handleMouseMove)
    }
  })
  return [
    {x, y}
  ]
}

// 使用
function Index() {
  const [position] = usePosition()
  return(
    

x:{position.x},y:{position.y}

) } export default Index

It can be clearly seen that using hooks is more convenient for logic reuse, and the logic is clearer when used.

Some common API uses of hooks

1, useState

Syntax

const [value, setValue] = useState(0)

This syntax is the ES6 array structure. The first value of the array is the declared state, and the second value is the state change function.

Each frame has an independent state

My personal understanding is that the independent state of each frame is achieved using the closure method.

function Example() {
  const [val, setVal] = useState(0)
  const timeoutFn = () => {
      setTimeout(() => {
        // 取得的值是点击按钮的状态,不是最新的状态
          console.log(val)
      }, 1000)
  }
  return (
      <>
          

{val}

) }

When the component's status or props are updated, the function component will be re-invoked for rendering, and each rendering is independent and has its own independent props and state, and will not affect other renderings.

2. useEffect

Syntax

useEffect(() => {
    //handler function...
    
    return () => {
        // clean side effect
    }
}, [//dep...])

useEffect receives a callback function and dependencies when the dependencies change Only then will the callback function inside be executed. useEffect is similar to the life cycle functions of class components didMount, didUpdate, and willUnmount.

Note

  • useEffect is asynchronous and will not be executed until the component is rendered

  • The callback function of useEffect can only return a processing function that clears side effects or does not return

  • If the dependency passed in by useEffect is an empty array, the function inside useEffect will only be executed once

3. useMemo, useCallback

useMemo and useCallback are mainly used to reduce the number of component updates and optimize component performance.

  • useMemo receives a callback function and dependencies, and the callback function will be re-executed only when the dependencies change.

  • useCallback receives a callback function and dependencies, and returns the memorized version of the callback function. The memorized version will only be re-memorized when the dependencies change.

Syntax

const memoDate = useMemo(() => data, [//dep...])
const memoCb = useCallback(() => {//...}, [//dep...])

When optimizing component performance, we generally use React.PureComponent for class components. PureComponent will perform a comparison on shouldUpdate. Determine whether updates are needed; for function components we generally use React.memo. But when using react hooks, since each rendering update is independent (new state is generated), even if React.memo is used, it will still be re-rendered.

比如下面这种场景,改变子组件的name值后由于父组件更新后每次都会生成新值(addAge函数会改变),所以子组件也会重新渲染。

function Parent() {
  const [name, setName] = useState('cc')
  const [age, setAge] = useState(22)

  const addAge = () => {
    setAge(age + 1)
  }

  return (
    <>
      

父组件

setName(e.target.value)} />

age: {age}

-------------------------

) } const Child = memo((props) => { const { addAge } = props console.log('child component update') return ( <>

子组件

) })

使用useCallback优化

function Parent() {
  const [name, setName] = useState('cc')
  const [age, setAge] = useState(22)

  const addAge = useCallback(() => {
    setAge(age + 1)
  }, [age])

  return (
    <>
      

父组件

setName(e.target.value)} />

age: {age}

-------------------------

) } const Child = memo((props) => { const { addAge } = props console.log('child component update') return ( <>

子组件

) })

只有useCallback的依赖性发生变化时,才会重新生成memorize函数。所以当改变name的状态是addAge不会变化。

4、useRef

useRef类似于react.createRef。

const node = useRef(initRef)

useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数(initRef)

作用在DOM上

const node = useRef(null)

这样可以通过node.current属性访问到该DOM元素。

需要注意的是useRef创建的对象在组件的整个生命周期内保持不变,也就是说每次重新渲染函数组件时,返回的ref 对象都是同一个(使用 React.createRef ,每次重新渲染组件都会重新创建 ref)。

5、useReducer

useReducer类似于redux中的reducer。

语法

const [state, dispatch] = useReducer(reducer, initstate)

useReducer传入一个计算函数和初始化state,类似于redux。通过返回的state我们可以访问状态,通过dispatch可以对状态作修改。

const initstate = 0;
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {number: state.number + 1};
    case 'decrement':
      return {number: state.number - 1};
    default:
      throw new Error();
  }
}
function Counter(){
    const [state, dispatch] = useReducer(reducer, initstate);
    return (
        <>
          Count: {state.number}
          
          
        
    )
}

6、useContext

通过useContext我们可以更加方便的获取上层组件提供的context。

父组件

import React, { createContext, Children } from 'react'
import Child from './child'

export const MyContext = createContext()

export default function Parent() {

  return (
    dc6dce4a544fdca2df29d5ac0ea9906b
      e388a4556c0f65e1904146cc1a846beeParent94b3e26ee717c64999d7867364b1b4a3
      6c114b46cb8836ff0ac83d93f4259369
        b709c9e9a1f23de0af93c9c27ea4dcef
      8e66e6aff1f0a13ebced51b2c1b5d182
    16b28748ea4df4d9c2150843fecfba68
  )
}

子组件

import React, { useContext } from 'react'
import { MyContext } from './parent'

export default function Parent() {
  const data = useContext(MyContext) // 获取父组件提供的context
  console.log(data)
  return (
    

Child

) }

使用步骤

  • 父组件创建并导出context:export const MyContext = createContext()
  • 父组件使用providervalue提供值:48721ce1b4e79a5bb092f89212a3882a
  • 子组件导入父组件的context:import { MyContext } from './parent'
  • 获取父组件提供的值:const data = useContext(MyContext)

不过在多数情况下我们都不建议使用context,因为会增加组件的耦合性。

7、useLayoutEffect

useEffect 在全部渲染完毕后才会执行;useLayoutEffect 会在 浏览器 layout之后,painting之前执行,并且会柱塞DOM;可以使用它来读取 DOM 布局并同步触发重渲染。

export default function LayoutEffect() {
  const [color, setColor] = useState('red')
  useLayoutEffect(() => {
      alert(color) // 会阻塞DOM的渲染
  });
  useEffect(() => {
      alert(color) // 不会阻塞
  })
  return (
      <>
        
颜色
) }

上面的例子中useLayoutEffect会在painting之前执行,useEffect在painting之后执行。

hooks让函数组件拥有了内部状态、生命周期,使用hooks让代码更加的简介,自定义hooks方便了对逻辑的复用,并且摆脱了class组件的this问题;但是在使用hooks时会产生一些闭包问题,需要仔细使用。

【相关推荐:Redis视频教程

The above is the detailed content of What are the differences between react hook and class?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn