npx
- 避免安装全局模块
- 调用项目内部安装的模块
npm run会新建一个shell,并将node_modules加入到系统环境变量,运行完再删除
为什么要有React Hook
- 组件很难复用状态逻辑
- 复杂组件难以理解,尤其是生命周期函数
- React组件一直是函数,使用Hook完全拥抱函数
useState
- 会触发组件的render
import React, {useState} from 'react'
const LikeButton: React.FC = () => {
const [like, setLike] = useState(0)
const [on, setOn] = useState(true)
return (
<>
<button onClick={() => {setLike( like + 1)}}>
{like} 赞
</button>
<button onClick={() => {setOn(!on)}}>
{on ? 'on' : 'off'}
</button>
</>
)
}
export default LikeButton;
复制代码
useEffect
无需清除的Effect
使用useEffect使用DOm完成标题更新
// 默认在第一次渲染之后,和每次更新之后都会执行
useEffect(() => {
document.title = `点击了${like}次`
})
复制代码
需要清除的Effect
使用useEffect完成一个鼠标跟踪器
import React, {useState, useEffect} from 'react'
const MouseTracker: React.FC = () => {
const [positions, setPositions] = useState({x: 0, y: 0})
useEffect(() => {
console.log('add effect', positions.x)
const mouseTracker = (e: MouseEvent) => {
console.log('inner')
setPositions({x: e.x, y: e.y})
}
document.addEventListener('click', mouseTracker)
return () => {
console.log('remove effect', positions.x)
document.removeEventListener('click', mouseTracker)
}
})
console.log('before render', positions.x)
return (
<p>X: {positions.x}, Y: {positions.y}</p>
)
}
export default MouseTracker
复制代码
add effect总是在before render之后执行
控制useEffect的执行
useEffect(() => {
console.log('add effect', positions.x)
const mouseTracker = (e: MouseEvent) => {
console.log('inner')
setPositions({x: e.x, y: e.y})
}
document.addEventListener('click', mouseTracker)
return () => {
console.log('remove effect', positions.x)
document.removeEventListener('click', mouseTracker)
}
}, [])
复制代码
这里实际就是componentDidMount和componentWillUnmount
自定义Hook
- 将组件逻辑提取到可重用的函数中
- 代码:使用自定义Hook抽象鼠标跟踪器
import React, {useState, useEffect} from 'react'
const useMousePosition = () => {
const [positions, setPositions] = useState({x: 0, y: 0})
useEffect(() => {
console.log('add effect', positions.x)
const mouseTracker = (e: MouseEvent) => {
console.log('inner')
setPositions({x: e.x, y: e.y})
}
document.addEventListener('mousemove', mouseTracker)
return () => {
console.log('remove effect', positions.x)
document.removeEventListener('mousemove', mouseTracker)
}
}, [])
return positions;
}
export default useMousePosition
复制代码
HOC 高阶组件
- 高阶组件就是一个函数,接受一个组件作为参数,返回一个新的组件
- 常见实现方法:属性代理和反向继承
- 劣势:
- 添加不必要的界面结构,而不是单纯的逻辑
- 难以理解
- 想要理解,还需要去找被包裹的组件
使用自定义hook完成useURLLoader
import {useState, useEffect} from 'react'
import axios from "axios";
const useURLLoader = (url: string, deps: any[] = []) => {
const [data, setData] = useState<any>(null);
const [loading, setLoading] = useState(false)
useEffect(() => {
setLoading(true)
axios.get(url).then(res => {
setData(res.data)
setLoading(false)
})
},deps)
return [data, loading]
}
export default useURLLoader;
复制代码
useRef
为了解决什么问题
- 任意一次渲染中的state值都是常量,不会随着时间改变而变,渲染输出会变,是因为组件被一次次调用,而每一次调用组件渲染时里面的state值独立于其他渲染。
- 在任意一次渲染中props和state值是始终保持不变的,如果props和state在不同的渲染中是相互独立的,那么使用到他们任何值也是相互独立的。
作用
- 多次渲染之间的纽带
- useRef在所有的render中保持唯一的引用
- 需要注意的是对ref值改变不会重新render
import React, {useState, useEffect, useRef} from 'react'
const LikeButton: React.FC = () => {
const [like, setLike] = useState(0)
// {current: 0}
const likeRef = useRef(0)
// 默认在第一次渲染之后,和每次更新之后都会执行
useEffect(() => {
document.title = `点击了${like}次`
})
function handleAlertClick(){
setTimeout(() => {
alert(`点击了 ${likeRef.current} 次`)
},3000)
}
return (
<>
<button onClick={() => {
setLike(like + 1)
likeRef.current++;
}}>
{like} 赞
</button>
<button onClick={handleAlertClick}>Alert!</button>
</>
)
}
export default LikeButton;
复制代码
- 模拟componentDidUpdate生命周期
import React, {useState, useEffect, useRef} from 'react'
const LikeButton: React.FC = () => {
const didMountRef = useRef(false)
// 模拟componentDidUpdate
useEffect(() => {
if (didMountRef.current) {
console.log('this is updated')
} else {
didMountRef.current = true;
}
})
return (
<>
</>
)
}
export default LikeButton;
复制代码
- 访问dom节点
import React, {useState, useEffect, useRef} from 'react'
const LikeButton: React.FC = () => {
const domRef = useRef<HTMLInputElement>(null)
// 将input focus
useEffect(() => {
if(domRef && domRef.current){
domRef.current.focus()
}
})
return (
<>
<input type="text" ref={domRef}/>
</>
)
}
export default LikeButton;
复制代码
useContext
- 解决多层传递属性
Hook规则
- 只在最顶层使用hook
- 只在React函数中调用hook
其他hook
- useReducer:简化有复杂逻辑的useState
- useCallback
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END