useEffect 可以在组件渲染后实现各种不同的副作用。通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。
useEffect告诉react在渲染后要去做什么,就是渲染后执行里面的函数,且执行的较晚
useEffect(()=>{
//平常执行的函数
return()=>{
//点击销毁后执行的函数
}
},[]) //[]表示根据什么而改变的
1、只有一个参数时
相当于componentDidMount和
componentDidUpdate
useEffect(() => {
console.log("count", count);
});
2、有两个参数时
2-1 第二个参数是[]时,相当于componentDidMount
useEffect(() => {
console.log("num", num);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
2-2 第二个参数有值时,只有当[]中的值改变时useEffect
才会生效
useEffect(() => {
console.log("count", count);
console.log("num", num);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [num]);
3、卸载
useEffect(() => {
console.log("login");
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// 当props.friend.id发生变化时,将会先进行清除工作
return () => {
console.log("logout");
ChatAPI.unsubscribeFromFriendStatus(props.friend.id);
};
}, [props.friend.id]);
整个过程就像
// Mount with { friend: { id: 100 } } props
ChatAPI.subscribeToFriendStatus(100, handleStatusChange); // 首次加载运行第一个 effect
// Update with { friend: { id: 200 } } props
ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // 先清除上一个 effect
ChatAPI.subscribeToFriendStatus(200, handleStatusChange); // 再运行下一个 effect
// Update with { friend: { id: 300 } } props
ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // 先清除上一个 effect
ChatAPI.subscribeToFriendStatus(300, handleStatusChange); // 再运行下一个 effect
// Unmount
ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // 清除最后一个 effect
这是一个最基本的useEffect例子,利用useState替代了类组件里面的componentDidMount和componentDidUpdate
function Example() {
const [count, setCount] = useState(0);
//只要有重新渲染就会执行useEffect
useEffect(() => {
//比如这个document.title是函数作用域之外的事务,或者打开数据库,调用其他的函数
//没有第二个参数,所以每次重新渲染都会被执行
document.title = `Example ${count} times`;
console.log("Example click");
});
//第一个参数告诉react渲染完后要去执行什么内容,第二个参数告诉react什么时候执行
//当第二个参数执行的时候才会发生变化,[]只执行一次,就是react渲染完后执行的那一次,相当于componentDidMount
//之后再点击按钮进行重新渲染就不会影响到它
useEffect(() => {
console.log("Example render once");
}, []);
return (
<div>
<p>click {count}</p>
<button onClick={() => setCount(count + 1)}>click me</button>
<button onClick={() => setCount(count)}>不变</button>
</div>
);
}
以下代码是用class表示的
class Example1 extends React.Component {
state = { count: 1 };
componentDidMount() {
document.title = `Example1 clicked ${this.state.count} first`;
console.log(document.title);
}
componentDidUpdate() {
document.title = `Example1 clicked ${this.state.count} time2`;
console.log(document.title);
}
render() {
return (
<div>
<p>clicked {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 2 })}>
click me
</button>
</div>
);
}
}
相比而言,useEffect简单了许多
案例一
function GithubUsers() {
const [users, setUsers] = useState([]);
useEffect(() => {
axios({
type: "GET",
url: "https://api.github.com/users",
}).then((response) => {
setUsers(response.data);
});
}, []);
return (
<div className="section">
{/* 渲染了两次是因为,第一次函数全部运行一遍,先输出一次,第二次因为setUser重新渲染又执行了一次 */}
{console.log("GithubUsers 我渲染了两次")}
{users.map((user) => (
<div key={user.id} className="card">
<h5>{user.login}</h5>
</div>
))}
</div>
);
}
完整案例
import React from 'react'
import { useState, useEffect } from 'react';
const ChatAPI = {
handle: null,
isOnline: false,
login: function () {
this.isOnline = true
//这里面的函数是执行订阅完后传回来的函数 handleStatusChange
if (this.handle) this.handle({ isOnline: true })
},
logout: function () {
this.isOnline = false
if (this.handle) this.handle({ isOnline: false })
},
subscribeToFriendStatus: function (id, handle) {
console.log(`订阅 用户id:${id}`);
//接收函数
this.handle = handle
},
unsubscribeFromFriendStatus: function (id) {
console.log(`清理 用户id:${id}`);
this.handle = null
},
}
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null)
//设置在线还是不在线的一种状态
function handleStatusChange(status) {
setIsOnline(status.isOnline)
}
//条件发生变化时。先会清理掉之前的effect,再执行下一个effect
useEffect(() => {
//函数执行完后subscribeToFriendStatus将会被调用
console.log('login');//刷新页面后会直接显示
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange)
//返回的函数在组件卸载的时候执行
return () => {
console.log('logout');//点击卸载组件后才会显示
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange)
}
}, [props.friend.id])//仅当id改变时,才会重新订阅
if (isOnline === null) {
return 'loading..'
}
return (
<div>
{console.log('FriendStatus 刷新')}
{isOnline ? 'Online' : "Offline"}
</div>
)
}
function App() {
const [show, setShow] = useState(true)
const [count, setCount] = useState(0)
const [userId, setUserId] = useState(1)
return (
<div>
userId:{userId} <br />
计数器:{count} <button onClick={() => setCount(count + 1)}>改变计数器</button> <br />
{show ? <FriendStatus friend={{ id: userId, name: 'tom' }} /> : null}
<button onClick={() => setShow(!show)}>显示/关闭</button>
<button onClick={() => setUserId(userId + 1)}>userId+1</button>
<button onClick={() => ChatAPI.login()}>登录</button>
<button onClick={() => ChatAPI.logout()}>退出</button>
</div>
)
}
export default App