react中的Hook函数,优点。(函数之useEffect)作用,语法,使用

目录

Hook概念

为什么用Hook

Hook的优点

useEffect

作用

什么是副作用

语法

使用

在没有任何依赖情况下使用

在有依赖的情况下使用

清除副作用函数

useEffect和useLayoutEffec的区别


Hook概念

  • Hook React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性
  • Hook 是一些可以让你在函数组件里钩入” React state 及生命周期等特性的函数
  • Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React

为什么用Hook

1. 更简洁:使用 Hook 可以让你的代码更加简洁和易读。相比于传统的类组件,使用函数组件配合 Hook 可以省去冗余的样板代码和生命周期方法,使代码更加简洁明了。

2. 更容易复用逻辑:Hook 提供了一种将组件逻辑进行复用的方式。通过将相关逻辑封装成一个自定义的 Hook,可以在多个组件中共享该逻辑,达到代码的复用,提高开发效率。

3. 更好的可测试性:由于 Hook 的函数形式,可以更方便地对组件的逻辑进行单元测试。你可以直接针对 Hook 函数进行测试,而不用关心组件的渲染和生命周期方法。

4. 更好的状态管理:Hooks 提供了 `useState` 和 `useReducer` 来管理组件的状态。通过这些钩子,可以让状态逻辑更加清晰和简洁,并且可以使逻辑更加分离,方便管理和追踪状态的变化。

5. 更好的性能优化:使用 Hook 的 `useCallback` 和 `useMemo` 可以帮助你避免不必要的重复计算和重渲染,从而提升性能。

Hook的优点

1. 函数式编程:使用 Hook 可以将组件逻辑封装成可复用的函数,而不用依赖类组件和面向对象编程的概念。这样可以更方便地编写纯粹的函数式代码、遵循单一责任原则,并且可以更容易地进行测试和调试。

2. 代码复用:Hook 的特性使得许多常见的逻辑可以在组件之间进行复用。通过自定义 Hook,可以将一些通用逻辑抽象出来,并在多个组件中共享。这样可以减少重复代码的编写,提高代码的可维护性和可读性。

3. 无需编写类组件:使用 Hook 可以避免编写类组件和相关的生命周期方法。类组件的结构通常会更复杂,包含了 constructor、render、componentDidMount 等生命周期方法,而 Hook 可以将状态逻辑和副作用操作直接写在函数组件中,简化了组件的结构和书写方式。

4. 更灵活的状态管理:通过 useState 和 useReducer 等 Hook,可以更方便地管理组件的状态。相比于传统的 setState 方法,Hook 提供了更直观和简洁的方式来定义和更新状态变量,从而更好地管理组件的状态。

5. 副作用管理:使用 useEffect 和其他相关 Hook,可以更精确地控制副作用操作的执行时机。可以在组件渲染完成之后、依赖发生变化时或组件卸载之前执行一些副作用操作,例如数据获取、订阅和取消订阅等。这样可以提高组件的性能和效率,并且避免了繁琐的手动清理工作。

useEffect

作用
useEffect 就是一个 Effect Hook ,给函数组件增加了操作副作用的能力
它跟 class 组件中的 componentDidMount componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API
什么是副作用

副作用(Side Effect)指的是函数或表达式执行过程中除了返回值外对其它数据产生的影响。具体来说,副作用就是函数执行的一些附带效果,例如修改了全局变量、文件读写操作、网络请求、控制台输出等。这些副作用会改变函数外部的状态,导致系统的状态变得不确定,从而可能引发一些意想不到的问题。例如,当多个函数共享同一个全局变量时,如果其中一个函数修改了该变量,就会对其他函数产生未知的影响,从而引发难以预测和调试的问题。

在 React 中,副作用通常发生在组件渲染期间或生命周期函数中,例如:

  • 修改组件内部的 state、props 或 context

  • 发起网络请求获取数据

  • 订阅事件、添加事件监听器或重置事件监听器

  • 操作本地存储或浏览器的全局对象

  • 执行定时器或动画等操作

  • 直接操作 DOM 元素

为了处理这些副作用,React 提供了 useEffect 这个 Hook。通过 useEffect,我们可以在函数组件中执行副作用操作,并在组件更新或销毁时进行清理,以遵循 React 的声明式、可预测和可控制的设计原则。

语法

useEffect是一个回调函数,第一个参数是一个箭头函数,里面编写副作用的具体操作

第二个参数是可选的,是一个数组,用于指定副作用操作中使用到的依赖项。在依赖项发生变化时,useEffect 会再次运行。如果没有依赖项,可以省略这个参数,这时 useEffect 会在每次渲染时都运行

useEffect(() => {
// 在这里处理副作用
    return () => {
    // 清除副作用函数
}
}, [依赖的状态;空数组表示,不依赖])
使用
在没有任何依赖情况下使用

副作用操作只会在组件首次渲染时执行一次,类似于componentDidMount

import React, { useEffect, useState } from 'react'
export default function App() {
    const [list, setList] = useState([])
// 当useEffect不依赖与任何数据的时候useEffect的回调函数之后执行一次
    useEffect(() => { // 类似与componentDidMount
// 数据请请求
    fetch('data.json').then(res => {
return res.json()
}).then(data => {
// 设置list
setList(data);
})
})
return (
    <div id="root" className='app-root'>
        <ul>
            {
                list.map(item => (
                    <li key={ item.id }>{ item.title }</li>
                ))
        }
        </ul>
       </div>
    )
}
在有依赖的情况下使用
// components/List.js
export default function List(props) {
// 封装渲染的函数
const renderList = () => {
    return (
        props.list.map(item => (
            <input key={ item.id } type="checkbox" checked={ item.checked }
        onChange={ () => handleState(item.id) } />
    ))
    )
}
// 修改状态
    const handleState = id => {
        props.changeState(id)
    }
    return (
        <div>{ renderList() }</div>
    )
}
// components/Footer.js
import { useEffect, useState } from "react"
export default function Footer(props) {
const [checked, setChecked] = useState(false)
useEffect(() => { // 类似于
setChecked(props.list.every(item => item.checked));
}, [props.list])
return (
<div>
全选:<input type="checkbox" checked={ checked } onChange={ () =>
{} } />
</div>
)
}
import { useState } from 'react';
import List from './components/List';
import Footer from './components/Footer'
export default function App() {
const [ list, setList ] = useState([
{ id: 1, checked: false },
{ id: 2, checked: false },
{ id: 3, checked: false }
]);
// 修改复选框的状态
const changeState = id => {
// 将原数组拷贝一份
const copyList = [...list];
// 根据id获取下标
const idx = copyList.findIndex(item => item.id === id);
// 修改当前的状态
copyList[idx].checked = !copyList[idx].checked;
// 重新设置数组
setList(copyList)
}
return (
<div id="root" className='app-root'>
<List list={ list } changeState={ changeState } />
<Footer list={ list } />
</div>
)
}
useEffect 的第二个参数是一个数组,如果数组的值为空代表的是不依赖任何数据,但是如果这个时候要是你在useEffect 这个回调函数中依赖了其他数据,但是你没有在第二个参数中声明你依赖的数据,则当依赖的数据发生变化时,useEffect这个回调函数不会再次执行
当然我们也可以不传递第二个参数, useEffect 会自动判断你有没有依赖与其他数
据,从而判断是否执行 useEffect 这个回调函数 
清除副作用函数
// App.js
import { useState } from "react"
import Child from "./components/Child"
export default function App() {
const [ flag, setFlag ] = useState(true)
return (
<div>
<h1>我是父组件</h1>
<button onClick={ () => setFlag(false) }>点击销毁子组件</button>
<hr />
{ flag && <Child /> }
</div>
)
}
// components/Child.js
import React, { useEffect } from 'react'
export default function Child() {
useEffect(() => {
window.onresize = () => {
console.log('resize');
}
const timer = setInterval(() => {
console.log('setInterval');
}, 1000)
return () => { // componentWillUnmonnt
// 清除副作用
clearInterval(timer);
window.onresize = null;
}
})
return (
<div>Child</div>
)
}
当我们组件销毁的时候,往往会清除一些无用的垃圾,比如事件和定时器等。这个时候
我们在在 useEffect 中返回一个函数来清除副作用函数。这个函数在组件销毁的时候执
行或者依赖发生改变时执行
useEffectuseLayoutEffec的区别
简单来说就是调用时机不同, useLayoutEffect 和原来 componentDidMount &componentDidUpdate 一致,在 react 完成 DOM 更新后马上同步调用的代码,会阻塞页面渲
染。而 useEffect 是会在整个页面渲染完才会调用的代码
官方建议优先使用 useEffect
在实际使用时如果想避免 页面抖动 (在 useEffect 里修改 DOM 很有可能出现)的话,可以把
需要操作 DOM 的代码放在 useLayoutEffect 里。在这里做点 dom 操作,这些 dom 修改会和
react 做出的更改一起被一次性渲染到屏幕上,只有一次回流、重绘的代价

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值