一、useState
声明state
变量。React在重复渲染时记住当前的值,并提供最新的值给函数。可以通过setXxx
来更新当前的Xxx
。
例:const [count, setCount] = useState(0);
此处的count
是变量名,存储数值;setCount
是一个函数,通过它更新count
的值。当传递一个新的值给setCount
,React会重新渲染组件。
二、useEffect
在函数组件中执行副作用操作。有两种常见的副作用操作:需要清除的和不需要清除的。
副作用:数据获取、设置订阅、手动更改React组件中的DOM。
useEffect
会在第一次渲染之后
和每次更新之后
都会执行,通过给useEffect传入第二个参数,它是一个数组,仅在数组内数据变化时才会出发副作用useEffect的回调函数执行。如果传入一个空数组,则只会在组件渲染时执行一次。
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
(一)、无需清除的effect
无需清除的意思是:执行完某些操作后,就可以忽略它们了。
只是想在React更新Dom之后运行一些额外的代码,比如:发送网络请求、手动变更DOM、记录日志等。
useEffect(() => {
document.title = `You clicked ${count} times`;
});
(二)、需要清除的effect
需要清除的意思是:执行完副作用后要清除,要防止引起内存泄漏。
例如订阅外部数据源。
通过返回一个函数,React会在组件卸载时执行清除操作。
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// Specify how to clean up after this effect:
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
每个effect都可以返回一个清除函数(return)。
三、自定义Hook
案例:多个组件共用一个请求,比如:请求用户列表,就可以考虑把请求抽离成一个自定义Hook,方便在多个地方调用。
步骤;
1、新建useGetUser.js
(名字根据实际命名,但是必须是use
开头);
import React, { useState, useEffect } from 'react';
// 引入接口
import { getUserList } from './commonApi';
// props:调用时传入的参数
const UseGetUser = (props) => {
const [testList, setTestList] = useState([]);
useEffect(() => {
getUserList(props)
.then(res => {
let data = [];
if (res.status === 200) {
if (res.data.code === 200) {
let result = res.data.data;
for (let item of result) {
data.push({ ...item, key: item.id });
}
// 设置数值
setTestList(data);
} else {
message.destroy();
message.error(res.data.message);
}
} else {
message.destroy();
message.error('网络错误!');
}
})
.catch(err => {
console.log(err);
})
}, []);
// 把数据return出去
return testList;
}
export default UseGetUser;
2、使用自定义Hook
import React from 'react'
// 引入自定义Hook
import useGetUser from '../useGetUser';
function App() {
// 使用自定义Hook
const useProjectList = useGetUser({media: 'tt'});
return (
<div className="App">
{
useProjectList.map((item, index) => <span key={index}>{item}</span>)
}
</div>
)
}
export default App
参考来源:
四、useCallback
与useMemo
功能类似(官方文档提示:可以把useMemo作为性能优化的手段,但不要把它当做语义上的保证,将来可能会被遗忘。)
useCallback(fn, deps)
相当于 useMemo(( )=> fn, deps)
。
解决组件间的props
或state
变化时重复渲染的问题。
案例:父组件渲染时导致子组件也被渲染。
import React, { useEffect, useState, useCallback } from 'react'
function Child({ test, onFatherClick }) {
useEffect(() => {
onFatherClick()
}, [onFatherClick])
const onClickSon = () => {
onFatherClick()
}
return <div onClick={onClickSon}>{test}</div>
}
function Parent() {
const [count, setCount] = useState(0)
const increment = () => setCount(count + 1)
const [test, setTest] = useState('我从父组件来');
const onFatherClick = () => {
console.log('我被渲染了没');
};
return (
<div>
<button onClick={increment}>我是父组件,我点击了:{count}</button>
<Child
test={test}
onFatherClick={onFatherClick}
/>
</div>
);
}
export default Parent;
可以明显的看出,除了第一次渲染时,在之后的每一次点击时,子组件都会被渲染。这时候可以使用useCallback。
const onFatherClick = useCallback(() => {
console.log('我被渲染了没');
}, []);