React Hook学习

1.作用

在函数式组件中可以做到管理状态,和模仿生命周期函数等操作
 

2.State Hook

useState() :参数是初始值,返回的是当前state和更新state的函数(实际上组成一个数组)
 
const [count , setCount] = useState( 0 );
// 数组解构语法
 
但是声明一个对象或者数组时,更新state变量的操作是 替换它而不是合并它
(必须要生成一个新的地址)
import React, {useState} from 'react';

const Admin = () =>{
const [count , setCount] = useState(0);
const [obj ,setObj] = useState({name:'zs'});
return (
<div>
<h2>{count}</h2>
<button onClick={()=>{setCount(count+1)}}> change </button>

<h2>{obj.name}</h2>
<button onClick={()=>{setObj({name:'l4'})}}> change </button>
// 不生效
<button onClick={()=>{setObj(Object.assign(obj,{name:'lll'}))}}> change </button>
// 这样添加属性
<button onClick={()=>{setObj({...obj,age:20})}}> change </button>
</div>
)
}
export default Admin;

3.Effect Hook

副作用操作:如 数据获取,设置定时器,更改DOM

 

useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。

 

常见副作用操作分为:需要清除的 和 不需要清除的

1.不需要清除的effect

比如:发送网络请求,手动更新DOM,记录日志等

 

一般在Class中,都会放到 componentDidMount 和 componentDidUpdate 中。

但很多时候,我们需要在组件加载和更新时进行同样的操作,所以在class中我们需要在这 两种声明周期 调用两次

 

在Effect hook中:

  • useEffect 做了什么?:定义组件需要在渲染后执行的操作,会自动在执行DOM更新后调用

  • 为什么在组件内部调用 useEffect?:放在组件内部可以让我们可以直接访问组件内部变量(闭包机制)

  • useEffect 会在每次渲染后都执行吗?:会在 第一次渲染后 和 每次更新之后 都会执行,就不用去区分是挂载还是更新。每次运行effect时,DOM都已经更新完成。

 

2.需要清除的effect

比如:订阅外部数据源

需要进行清除,可以防止内存泄漏

在class中,会在 componentDidMount 中设置,在 componentWillUnmount 中清除

 

在effect hook中:

在effect中返回一个函数,react会在执行清除时调用它

  • 为什么要在 effect 中返回一个函数?:这是effect可选的清除机制,每个effect可以返回一个清除函数,这样可以把添加和移除订阅的逻辑放在一起。

  • React 何时清除 effect?: react会在组件卸载的时候执行清除操作(每次渲染的时候都会执行,所以react会在执行下一个effect之前对上一个effect进行清除)

 

可以使用多个effect实现关注点分离:

可以把不相关的逻辑分离在不同的effect中,并且把相同的逻辑放在同一个effect中

 

为什么每次更新的时候都要运行 Effect?

effect的清除阶段在每次重新渲染时都会执行,而不是只在卸载组件的时候执行一次,

场景:

componentDidMount() {
ChatAPI.subscribeToFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}

componentDidUpdate(prevProps) {
// 取消订阅之前的 friend.id
ChatAPI.unsubscribeFromFriendStatus(
prevProps.friend.id,
this.handleStatusChange
);
// 订阅新的 friend.id
ChatAPI.subscribeToFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}

componentWillUnmount() {
ChatAPI.unsubscribeFromFriendStatus(
this.props.friend.id,
this.handleStatusChange
);
}

当props中的id变化后需要在componentDidUpdate中对上一个进行清理,对下一个进行订阅。

 

而在Hook中还是:

useEffect(() => {
// ...
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};

这样不需要特定的代码来处理更新逻辑,每次渲染后都会对前一个清理,后一个订阅。

 

通过跳过 Effect 进行性能优化?

每次渲染后都执行清理或者执行 effect 可能会导致性能问题。

在class中我们会通过在 componentDidUpdate 中对 prevProps或者prevState 进行比较来解决:

componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
document.title = `You clicked ${this.state.count} times`;
}
}

而在hook里面,如果某些特定值在两次渲染中没有变化,可以通知react跳过对effect的调用:使用 useEffect的第二个可选参数的数组

useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新

当重新渲染时,count值不变,那么这个effect就被跳过了

 

如果想执行只运行一次的effect(只在组件挂载和卸载时执行),那么可以传递一个空数组[]作为第二个参数。即effect不依赖于props或者state中任何值,不需要重复执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值