搜索
首页web前端前端问答react hook和class的区别有哪些

react hook和class的区别有哪些

Mar 22, 2022 pm 12:12 PM
classreact hook

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

react hook和class的区别有哪些

本教程操作环境: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 (
      dc6dce4a544fdca2df29d5ac0ea9906b
        e388a4556c0f65e1904146cc1a846beeyou click { count }94b3e26ee717c64999d7867364b1b4a3
        58d87a863b0fd08858af212a24752208点击65281c5ac262bf6d81768915a4a77ac0
      16b28748ea4df4d9c2150843fecfba68
    )
  }
}

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 &#39;react&#39;

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(&#39;mousemove&#39;, this.handleMouseMove)
  }

  componentWillUnmount() {
    document.removeEventListener(&#39;mousemove&#39;, 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 &#39;react&#39;

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(&#39;mousemove&#39;, handleMouseMove)
    return () => {
      document.removeEventListener(&#39;mousemove&#39;, 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(&#39;cc&#39;)
  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(&#39;child component update&#39;)
  return (
    <>
      <p>子组件</p>
      <button onClick={addAge}>click</button>
    </>
  )
})

使用useCallback优化

function Parent() {
  const [name, setName] = useState(&#39;cc&#39;)
  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(&#39;child component update&#39;)
  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 &#39;increment&#39;:
      return {number: state.number + 1};
    case &#39;decrement&#39;:
      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: &#39;increment&#39;})}>+</button>
          <button onClick={() => dispatch({type: &#39;decrement&#39;})}>-</button>
        </>
    )
}

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 &#39;react&#39;
import { MyContext } from &#39;./parent&#39;

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

使用步骤

  • 父组件创建并导出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(&#39;red&#39;)
  useLayoutEffect(() => {
      alert(color) // 会阻塞DOM的渲染
  });
  useEffect(() => {
      alert(color) // 不会阻塞
  })
  return (
      <>
        <div id="myDiv" style={{ background: color }}>颜色</div>
        <button onClick={() => setColor(&#39;red&#39;)}>红</button>
        <button onClick={() => setColor(&#39;yellow&#39;)}>黄</button>
      </>
  )
}

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

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

【相关推荐:Redis视频教程

以上是react hook和class的区别有哪些的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
React的前端开发:优势和技术React的前端开发:优势和技术Apr 17, 2025 am 12:25 AM

React的优势在于其灵活性和高效性,具体表现在:1)组件化设计提高了代码重用性;2)虚拟DOM技术优化了性能,特别是在处理大量数据更新时;3)丰富的生态系统提供了大量第三方库和工具。通过理解React的工作原理和使用示例,可以掌握其核心概念和最佳实践,从而构建高效、可维护的用户界面。

反应与其他框架:比较和对比选项反应与其他框架:比较和对比选项Apr 17, 2025 am 12:23 AM

React是一个用于构建用户界面的JavaScript库,适用于大型和复杂的应用。1.React的核心是组件化和虚拟DOM,提高了UI渲染性能。2.与Vue相比,React更灵活但学习曲线较陡,适合大型项目。3.与Angular相比,React更轻量,依赖社区生态,适用于需要灵活性的项目。

在HTML中脱神秘的React:这一切如何工作在HTML中脱神秘的React:这一切如何工作Apr 17, 2025 am 12:21 AM

React通过虚拟DOM在HTML中运作。1)React使用JSX语法编写类似HTML的结构。2)虚拟DOM管理UI更新,通过Diffing算法高效渲染。3)使用ReactDOM.render()将组件渲染到真实DOM。4)优化和最佳实践包括使用React.memo和组件拆分,提升性能和可维护性。

反应行动:现实应用程序的示例反应行动:现实应用程序的示例Apr 17, 2025 am 12:20 AM

React在电商、社交媒体和数据可视化等领域有广泛应用。1)电商平台使用React构建购物车组件,利用useState管理状态,onClick处理事件,map函数渲染列表。2)社交媒体应用通过useEffect与API交互,展示动态内容。3)数据可视化使用react-chartjs-2库渲染图表,组件化设计便于嵌入应用。

带有React的前端体系结构:最佳实践带有React的前端体系结构:最佳实践Apr 17, 2025 am 12:10 AM

React前端架构的最佳实践包括:1.组件设计与复用:设计单一职责、易于理解和测试的组件,实现高度复用。2.状态管理:使用useState、useReducer、ContextAPI或Redux/MobX管理状态,避免过度复杂。3.性能优化:通过React.memo、useCallback、useMemo等方法优化性能,找到平衡点。4.代码组织与模块化:按功能模块组织代码,提高可管理性和可维护性。5.测试与质量保证:使用Jest和ReactTestingLibrary进行测试,确保代码质量和可靠

html内部的反应:集成了动态网页的JavaScripthtml内部的反应:集成了动态网页的JavaScriptApr 16, 2025 am 12:06 AM

要将React集成到HTML中,需遵循以下步骤:1.在HTML文件中引入React和ReactDOM。2.定义一个React组件。3.使用ReactDOM将组件渲染到HTML元素中。通过这些步骤,可以将静态HTML页面转化为动态、交互式的体验。

反应的好处:性能,可重用性等等反应的好处:性能,可重用性等等Apr 15, 2025 am 12:05 AM

React受欢迎的原因包括其性能优化、组件复用和丰富的生态系统。1.性能优化通过虚拟DOM和diffing机制实现高效更新。2.组件复用通过可复用组件减少重复代码。3.丰富的生态系统和单向数据流增强了开发体验。

反应:创建动态和交互式用户界面反应:创建动态和交互式用户界面Apr 14, 2025 am 12:08 AM

React是构建动态和交互式用户界面的首选工具。1)组件化与JSX使UI拆分和复用变得简单。2)状态管理通过useState钩子实现,触发UI更新。3)事件处理机制响应用户交互,提升用户体验。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中