重学前端-Hooks
更新日期:11-7
第一次更新:11-7
第二次更新:11-13
第三次更新:11-14
1、React Hooks 介绍
1、React Hooks 是⽤来做什么的
对函数型组件进⾏增强, 让函数型组件可以存储状态, 可以拥有处理副作⽤的能⼒.
让开发者在不使⽤类组件的情况下, 实现相同的功能.
2、React Hooks 使⽤
1、useState说明
使用闭包来实现保存数据状态,页面重新渲染时状态保持不变
- 接收唯⼀的参数即状态初始值. 初始值可以是任意数据类型.
- 返回值为数组. 数组中存储状态值和更改状态值的⽅法. ⽅法名称约定以set开头, 后⾯加上状态名称.
- ⽅法可以被调⽤多次. ⽤以保存不同状态值.
- 参数可以是⼀个函数, 函数返回什么, 初始状态就是什么, 函数只会被调⽤⼀次(组件第一次被渲染的时候得到执行), ⽤在初始值是动态值的情况.
setState会用新的状态值替换老的状态值
只修改对象中age的做法
const [person,setPerson] = useState({name:'李四',age:20})
<button onClick = {() => setPerson({...person,age:30})}>setPerson</button>
useState初始值传递函数的情况
传递函数只会被执行一次
const [count, setCount] = useState(()=>{
return props.count || 0
})
设置状态值方法的特性
设置状态值的方法可以是一个值也可以是一个函数(带有一个形参也就是保存的状态值)
设置状态的方法本身是异步的
异步解决方案:
function handleCount(){
setCount(count =>{
const newCount = count +1
document.title = newCount
return newCount
})
}
function handleCount(){
setCount(count =>{
document.title = count +1
return count +1
})
}
2、useReducer()
useState()拓展
3、useContext()
在跨组件层级获取数据时简化获取数据的代码
const countContext = createContext();
function App(){
return <countContext.Provide value={100}>
<Foo />
</countContext.Provide>
}
function Foo(){
const value = useContext(countContext);
return <div>{value}</>
}
3、useEffect
让函数式组件拥有处理副作用的能力,类似于生命周期
解决问题:按照用途将代码进行分类(将一组相干的逻辑归置到同一个副作用函数中)
简化重复代码,使组件内部代码更加清晰
//组件挂载完成之后执行,组件更新完成之后执行
useEffect(()=>{
console.log('组件挂载完成,更新完成')
})
//组件挂载完成之后执行一次
useEffect(()=>{
console.log('组件挂载完成')
},[])
//组件被卸载之前执行
useEffect(()=>{
return ()=>{
console.log('组件被卸载')
}
},[])
//卸载组件
ReactDOM.unmountComponentAtNode(document.getElementById('root'))
案例:
//为window对象添加滚动事件
//组件挂载完成绑定,在组件卸载之前解绑
useEffect(()=>{
window.addEventListener('scroll',onScroll)
return()=>{
window.removeEventListener('scroll',onScroll)
}
},[])
//设置定时器让count数值每隔一秒增加1
useEffect(()=>{
const timerId = setInterval(()=>{
setCount(()=>count+1)
},1000)
return ()=>{
clearInterval(timerId)
}
},[])
useEffect第二个参数:只有指定数据发生变化时触发effect
useEffect结合异步函数
useEffect中的参数函数不能是异步函数,因为useEffect函数要返回清理资源的函数,如果是异步函数就变成返回Promise
useEffect(()=>{
(async function(){
let res = await getData()
}
)
},[])
4、useMemo
1、useMemo
类似于vue中的计算属性,用于监测某个值的变化,根据变化值计算新值,返回计算出来的新值
特点:会缓存结果(缓存值),如果监测值没有发生变化,即使组件重新渲染,也不会重新计算
传入两个参数,要执行的函数以及监测的值,当监测的值发生改变后执行回调函数
2、memo方法
如果组件数据没有发生变化,阻止组件更新,类似PureComponent和shouldComponentUpdate
memo方法传入一个function返回一个新组件
5、useCallback
性能优化,缓存函数,使组件渲染时得到相同的函数实例
说明:当父组件的值发生改变,父组件重新渲染,组件重新渲染生成了不同的函数实例,也就是说每一次给子组件传递的都是不同的函数,导致子组件重新渲染,父组件中的函数实例和上一次组件中调用的函数实例不是同一个。相当于给子组件传递了一个不同的函数,函数的变化导致子组件又发生重新渲染,使用callback优化使函数每次得到的都是同一个实例
一般场景:父组件给子组件传递函数做一层callback优化
6、useRef
1、基本使用
获取DOM元素对象
2、保存数据(跨组件周期)
即使组件重新渲染,保存的数据仍然存在,保存的数据被更改不会触发组件重新渲染
跨组件周期:组件重新渲染不丢失
useState:保存状态数据,当数据发生改变触发组件重新渲染
useRef:不属于状态数据,更改了也不会导致组件重新渲染
//使用场景
// 存在问题:无法清除定时器,在定时器中使用setCount更改页面数据的值,当值发生改变,组件重新渲染,timeId被重新定义,点击按钮清除的就是空的timeId,当组件重新渲染后,timeId已经丢失
function App() {
const [count, setCount] = useState(0);
let timeId = null;
useEffect(() => {
timeId = setInterval(() => {
setCount(count => count + 1);
}, 1000);
}, []);
const stopCount = () => {
clearInterval(timeId);
};
return (
<div>
{count}
<button onClick={stopCount}>停止</button>
</div>
);
}
// 解决方案,当组件重新渲染后,timeId不被重置,即保存timeId
function App() {
const [count, setCount] = useState(0);
let timeId = useRef();
useEffect(() => {
timeId.current = setInterval(() => {
setCount(count => count + 1);
}, 1000);
}, []);
const stopCount = () => {
clearInterval(timeId.current);
};
return (
<div>
{count}
<button onClick={stopCount}>停止</button>
</div>
);
}
3、⾃定义 Hook
- 自定义hook使标准的封装和共享逻辑的方式
- 自定义hook是一个函数,以use开头
- 自定义hook其实就是逻辑和内置hook的组合
//自定义hook复用逻辑
function useUpdateInput(initialValue) {
const [value, setValue] = useState(initialValue);
return {
value,
onChange: event => setValue(event.target.value),
};
}
function App() {
const usernameInput = useUpdateInput('');
const passwordInput = useUpdateInput('');
const submitForm = event => {
event.preventDefault();
console.log(usernameInput.value);
console.log(passwordInput.value);
};
return (
<form onSubmit={submitForm}>
<input type='text' name='username' {...usernameInput} />
<input type='password' name='password' {...passwordInput} />
<input type='submit' />
</form>
);
}
4、React 路由 Hooks
react-router-dom路由提供的钩子函数
实现目的:获取路由信息
useHistory
useLocation
useRouteMatch
useParams(常用)