我的编程空间,编程开发者的网络收藏夹
学习永远不晚

react hook和class的区别是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

react hook和class的区别是什么

这篇文章主要介绍“react hook和class的区别是什么”,在日常操作中,相信很多人在react hook和class的区别是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”react hook和class的区别是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

区别:1、hooks的写法比class简洁;2、hooks的业务代码比class更加聚合;3、class组件的逻辑复用通常用render props以及HOC两种方式,而react hooks提供了自定义hooks来复用逻辑。

本教程操作环境:Windows7系统、react17.0.1版、Dell G3电脑。

react hooks与class组件有哪些区别?下面就来带大家对比一下react hooks和class组件,聊聊它们的区别。

react-hooks解决的问题

  • 函数组件中不能拥有自己的状态(state)。在hooks之前函数组件是无状态的,都是通过props来获取父组件的状态,但是hooks提供了useState来维护函数组件内部的状态。

  • 函数组件中不能监听组件的生命周期。useEffect聚合了多个生命周期函数。

  • class组件中生命周期较为复杂(在15版本到16版本的变化大)。

  • class组件逻辑难以复用(HOC,render props)。

hooks对比class的好处(对比)

1、写法更加的简洁

我们以最简单的计数器为例:

class组件

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 (
      <div>
        <p>you click { count }</p>
        <button onClick={this.handleClick}>点击</button>
      </div>
    )
  }
}

hooks

function ExampleOfHooks() {
    const [count, setCount] = useState(0)
    const handleClick = () => {
        setCount(count + 1)
    }
    return (
      <div>
        <p>you click { count }</p>
        <button onClick={handleClick}>点击</button>
      </div>
    )
}

可以看到使用hooks的代码相比class组件代码更加的简洁、清晰。

2、业务代码更加聚合

使用class组件经常会出现一个功能出现在两个生命周期函数内的情况,这样分开写有时候可能会忘记。比如:

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

由于添加定时器和清除定时器是在两个不同的生命周期函数,中间可能会有很多其他的业务代码,所以可能会忘记清除定时器,如果在组件卸载时没有添加清楚定时器的函数就可能会造成内存泄漏、网络一直请求等问题。

但是使用hooks可以让代码更加的集中,方便我们管理,也不容易忘记:

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

3、逻辑复用方便

class组件的逻辑复用通常用render props以及HOC两种方式。react hooks提供了自定义hooks来复用逻辑。

下面以获取鼠标在页面的位置的逻辑复用为例:

class组件render props方式复用

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(
      <div>
        {
          children({x, y})
        }
      </div>
    )
  }

}

// 使用
class Index extends Component {
  constructor(props) {
    super(props)
  }

  render() {
    return (
      <MousePosition>
        {
          ({x, y}) => {
            return (
              <div>
                <p>x:{x}, y: {y}</p>
              </div>
            )
          }
        }
      </MousePosition>
    )
  }
}

export default Index

自定义hooks方式复用

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(
    <div>
      <p>x:{position.x},y:{position.y}</p>
    </div>
  )
}

export default Index

可以很明显的看出使用hooks对逻辑复用更加的方便,使用的时候逻辑也更加清晰。

hooks常见的一些API使用

1、useState

语法

const [value, setValue] = useState(0)

这种语法方式是ES6的数组结构,数组的第一个值是声明的状态,第二个值是状态的改变函数。

每一帧都有独立的状态

个人理解针对每一帧独立的状态是采用了闭包的方法来实现的。

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

当组件的状态或者props更新时,该函数组件会被重新调用渲染,并且每一次的渲染都是独立的都有自己独立的props以及state,不会影响其他的渲染。

2、useEffect

语法

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

useEffect接收一个回调函数以及依赖项,当依赖项发生变化时才会执行里面的回调函数。useEffect类似于class组件didMount、didUpdate、willUnmount的生命周期函数。

注意点

  • useEffect是异步的在组件渲染完成后才会执行

  • useEffect的回调函数只能返回一个清除副作用的处理函数或者不返回

  • 如果useEffect传入的依赖项是空数组那么useEffect内部的函数只会执行一次

3、useMemo、useCallback

useMemo和useCallback主要用于减少组件的更新次数、优化组件性能的。

  • useMemo接收一个回调函数以及依赖项,只有依赖项变化时才会重新执行回调函数。

  • useCallback接收一个回调函数以及依赖项,并且返回该回调函数的memorize版本,只有在依赖项重新变化时才会重新新的memorize版本。

语法

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

在优化组件性能时针对class组件我们一般使用React.PureComponent,PureComponent会在shouldUpdate进行一次钱比较,判断是否需要更新;针对函数组件我们一般使用React.memo。但是在使用react hooks时由于每一次渲染更新都是独立的(生成了新的状态),即使使用了React.memo,也还是会重新渲染。

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

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

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

  return (
    <>
      <p>父组件</p>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <p>age: {age}</p>
      <p>-------------------------</p>
      <Child addAge={addAge} />
    </>
  )
}

const Child = memo((props) => {
  const { addAge } = props
  console.log('child component update')
  return (
    <>
      <p>子组件</p>
      <button onClick={addAge}>click</button>
    </>
  )
})

使用useCallback优化

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

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

  return (
    <>
      <p>父组件</p>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <p>age: {age}</p>
      <p>-------------------------</p>
      <Child addAge={addAge} />
    </>
  )
}

const Child = memo((props) => {
  const { addAge } = props
  console.log('child component update')
  return (
    <>
      <p>子组件</p>
      <button onClick={addAge}>click</button>
    </>
  )
})

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

4、useRef

useRef类似于react.createRef。

const node = useRef(initRef)

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

作用在DOM上

const node = useRef(null)
<input ref={node} />

这样可以通过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}
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
        </>
    )
}

6、useContext

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

父组件

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

export const MyContext = createContext()

export default function Parent() {

  return (
    <div>
      <p>Parent</p>
      <MyContext.Provider value={{name: 'cc', age: 21}}>
        <Child />
      </MyContext.Provider>
    </div>
  )
}

子组件

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

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

使用步骤

  • 父组件创建并导出context:export const MyContext = createContext()

  • 父组件使用providervalue提供值:<MyContext.provide value={{name: 'cc', age: 22}} />

  • 子组件导入父组件的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 (
      <>
        <div id="myDiv" style={{ background: color }}>颜色</div>
        <button onClick={() => setColor('red')}>红</button>
        <button onClick={() => setColor('yellow')}>黄</button>
      </>
  )
}

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

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

到此,关于“react hook和class的区别是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

react hook和class的区别是什么

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

android插桩和hook的区别是什么

Android插桩和Hook是两种不同的技术,用于在Android应用程序中修改或拦截代码的执行。插桩(Instrumentation)是一种在编译或运行时修改已有代码的技术。它可以通过在代码中插入额外的指令或代码段来实现对目标代码的修改。
2023-09-20

abstract class和interface的区别是什么

本文小编为大家详细介绍“abstract class和interface的区别是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“abstract class和interface的区别是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢
2023-06-03

React的Hook是什么

这篇文章主要介绍了React的Hook是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。State Hook这个例子用来显示一个计数器。当你点击按钮,计数器的值就会增加:i
2023-06-29

vue和react的区别是什么

本文小编为大家详细介绍“vue和react的区别是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue和react的区别是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。具体分析如下:1.监听数据变化的实
2023-06-05

c++中class和struct的区别是什么

在C++中,class和struct都用于定义自定义的数据类型,但它们之间有几个区别。1. 默认的访问修饰符:在class中,默认的成员访问修饰符是private,而在struct中,默认的成员访问修饰符是public。2. 继承方式:在c
2023-09-15

synchronized加锁this和class的区别是什么

本篇内容介绍了“synchronized加锁this和class的区别是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!synchroni
2023-06-21

react中props和state的区别是什么

在React中,props和state是两个不同的概念,用于处理组件的数据。它们之间的区别如下:1. Props(属性):- Props是组件的属性,是从父组件传递给子组件的数据。- Props是只读的,子组件不能修改自己的props,只能
2023-09-13

c++中的struct和class有什么区别

struct 和 class 在 c++ 中创建自定义类型,主要区别如下:默认访问权限不同,struct 为 public,class 为 private。struct 分配在栈空间,class 分配在堆空间。struct 可通过 publ
c++中的struct和class有什么区别
2024-05-12

css中id与class的区别是什么

这篇文章主要介绍“css中id与class的区别是什么”,在日常操作中,相信很多人在css中id与class的区别是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”css中id与class的区别是什么”的疑
2023-06-20

vue和react的区别及优缺点是什么

这篇文章主要讲解了“vue和react的区别及优缺点是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue和react的区别及优缺点是什么”吧!vue和react的区别及优缺点共同点数据
2023-07-05

C++函数调用与Struct和CLass的区别是什么

本篇内容介绍了“C++函数调用与Struct和CLass的区别是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、结构回顾结构:自定义的
2023-06-30

C++类和对象之封装及class与struct的区别是什么

本篇内容主要讲解“C++类和对象之封装及class与struct的区别是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++类和对象之封装及class与struct的区别是什么”吧!封装的意
2023-06-30

css中class和id选择器有什么区别

这篇文章将为大家详细讲解有关css中class和id选择器有什么区别,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。什么是csscss是一种用来表现HTML或XML等文件样式的计算机语言,主要
2023-06-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录