简单的例子,简单计数器实现,抽离业务逻辑成为hook:
function useCounter() {
const [count, setCount] = useState(0)
const increment = useCallback(() => {
setCount(count + 1)
}, [count])
const decrement = useCallback(() => {
setCount(count - 1)
}, [count])
const reset = useCallback(() => {
setCount(0)
}, [count])
return { count, increment, decrement, reset }
}
在组件中使用这个hook:
function Counter() {
const { count, increment, decrement, reset } = useCounter()
return (
<div>
<p>{ count }</p>
<button onClick={decrement}>-</button>
<button onClick={increment}>+</button>
<button onClick={reset}>reset</button>
</div>
)
}
和高阶组件相比,更加简单
-
三个典型业务场景
-
封装通用逻辑:useAsync
-
如:发起异步请求获取数据并显示在界面上
-
处理这类请求时,模式都是类似的,通常遵循下面的步骤:
-
创建data、loading、error这3个state
-
请求发出后,设置loading state为true
-
请求成功后,将返回的数据放到某个state中,并将loading state设为false
-
请求失败后,设置error state为true,并将loading state设为false
最后,基于state、loading、error这三个state数据,UI就可以正确显示数据了
将逻辑抽离出来:
const useAsync = (asyncFunction) => {
// 设置3个异步逻辑相关的state
const [data, setDate] = useState(null)
cosnt [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
// 定义一个callback用于执行异步逻辑
const execute = useCallback(() => {
setLoading(true)
setData(null)
setError(null)
return asyncFunction()
.then((response) => {
setData(response)
setLoading(false)
})
.catch((erro) => {
setError(erro)
setLoading(false)
})
}, [asyncFunction])
return { execute, loading, data, error }
}
在组件中使用:
function UserList() {
const {
execute: fetchUsers,
data: users,
loading,
error
} => useAsync(async() => {
const res = await fetch("http://req/api/users/")
const json = await res.json()
return json.data // response
})
return (
// UI...
)
}
-
监听浏览器状态:useScroll
-
界面需要根据在窗口大小变化重新布局
-
在页面滚动时,需要根据滚动条位置,来决定是否显示一个“返回顶部”的按钮
-
对应到这个场景就是:
-组件需要绑定到当前滚动条的位置数据上
const getPosition = () => {
return {
x: document.body.scrollLeft,
y: document.body.scrollTop
}
}
const useScroll = () => {
const [position, setPosition] = useState(getPosition())
useEffect(() => {
const handler = () => {
setPosition(getPosition())
}
document.addEventListener("scroll", handler)
return () => {
document.removeEventListener("scroll", handler)
}
}, [])
return position
}
使用,是否展示返回顶部:
function ScrollTop {
const { y } = useScroll()
const goTop = useCallback(()=> {
document.body.scrollTop = 0
}, [])
// y会根据scroll动态改变
if ( y > 300 ) {
return (
<button onClick={goTop}>
Back to Top
</button>
)
}
return null
}