在 Taro Hooks 出来 以后就一直想着体验一波 Hooks 小程序开发,不过一直忙着补番 😌。最近补完了,就搞了起来,开发了 20 天左右(其实大部分时间都在改 UI😒),基本上是完成了,而后也上架了,遂跟你们分享一点心得 😈html
能够先扫描体验:git
网络不稳定的小伙伴看预览:github
在 GitHub Pro 的开发中,我写了四个 hooks,来帮助我复用一些重复的逻辑,提升开发效率小程序
接下来就分析一下它们的做用bash
做用同名字,用来进行网络请求,传入请求参数以及进行请求的函数,存储数据,返回 [currData, refresh]
,其中currData
是存储的返回数据,refresh
用于刷新请求。网络
function useRequest<T>(
params: any,
request: (params: any) => Promise<T | null>
): [T | null, () => void] | [] {
const [currData, setData] = useState<T | null>(null)
const [count, setCount] = useState(0)
const pagePullDownRef = useRef('')
useEffect(() => {
request(params).then(data => {
if (data) {
setData(data)
}
})
}, [count])
usePullDownRefresh(() => {
refresh()
})
useEffect(() => {
events.on(PULL_DOWN_REFRESH_EVENT, (page: string) => {
if (!pagePullDownRef.current) {
pagePullDownRef.current = page
} else if (pagePullDownRef.current !== page) {
return
}
refresh()
})
return () => {
events.off(PULL_DOWN_REFRESH_EVENT)
}
}, [])
const refresh = () => {
setCount(count + 1)
}
return [currData, refresh]
}
export default useRequest
复制代码
useRequestide
这个钩子是最复杂的一个,也是做用最大的一个函数。可以在滚动条到底底部的时候,请求下一页,加载更多的数据。函数
function useRequestWIthMore<T, S = string>(
data: S,
request: (data: S, params: any | null) => Promise<T[] | null>
): [T[] | null, boolean, () => void, () => void] | [] {
if (!data) {
// bug?
console.warn('useRequestWIthMore: no data')
return []
}
const [currData, setData] = useState<T[] | null>(null)
const [hasMore, setHasMore] = useState<boolean>(true)
const [params, setParams] = useState(defaultParams)
const loadingRef = useRef(false)
useEffect(() => {
if (hasMore) {
loadingRef.current = true
request(data, params)
.then(data => {
if (data) {
if (currData) {
setData([...currData, ...data])
} else {
setData(data)
}
if (data.length < params.per_page!) {
setHasMore(false)
}
}
})
.finally(() => {
loadingRef.current = false
Taro.stopPullDownRefresh()
Taro.hideLoading()
})
}
}, [params])
usePullDownRefresh(() => {
refresh()
})
useReachBottom(() => {
if (loadingRef.current) {
return
}
getMoreData()
})
const getMoreData = () => {
setParams(params => ({ ...params, page: params.page! + 1 }))
}
const refresh = () => {
setData(null)
setHasMore(true)
setParams({ ...params, page: 1 })
}
return [currData, hasMore, refresh, getMoreData]
}
复制代码
是否是很完美,惋惜不是这么简单。ui
Taro 中有个大坑就是在组件中没法使用如usePullDownRefresh
、useReachBottom
等钩子。spa
因此就引出来一个大问题 -- 如何在组件中触发这些操做呢。并且在 GitHub Pro 中,我把不少组件进行了拆分,难道我要重写?😑
这确定是不行的。还好贴心的 Taro 给咱们提供了一个消息机制(实际上就是发布订阅),能够用它来解决咱们当前遇到的问题。
// 存储惟一 id 用于匹配消息
const pageReachBottomRef = useRef('')
const pagePullDownRef = useRef('')
useEffect(() => {
events.on(REACH_BOTTOM_EVENT, (page: string) => {
if (loadingRef.current) {
return
}
if (!pageReachBottomRef.current) {
pageReachBottomRef.current = page
} else if (pageReachBottomRef.current !== page) {
return
}
getMoreData()
})
return () => {
events.off(REACH_BOTTOM_EVENT)
}
}, [])
useEffect(() => {
events.on(PULL_DOWN_REFRESH_EVENT, (page: string) => {
if (!pagePullDownRef.current) {
pagePullDownRef.current = page
} else if (pagePullDownRef.current !== page) {
return
}
refresh()
})
return () => {
events.off(PULL_DOWN_REFRESH_EVENT)
}
}, [])
复制代码
其中pageReachBottomRef
、pagePullDownRef
很是关键,用来对消息进行配对,防止说我这个页面滚动,致使另一个页面也进行数据的请求。
这个钩子用来作当下拉刷时候发送刷新页面的消息(在 page 内使用),而接受者就前面useRequestWithMore
了
function usePullDownRefreshEvent() {
const pageRef = useRef(getUniqueId())
usePullDownRefresh(() => {
events.trigger(PULL_DOWN_REFRESH_EVENT, pageRef.current)
})
return null
}
复制代码
这个钩子用来作当页面滚动到底部时候发送获取数据的消息(在 page 内使用),而接受者就前面useRequestWithMore
了,而且我在内部作了一下节流。
function useReachBottomEvent() {
const pageRef = useRef(getUniqueId())
const timerRef = useRef(0)
useReachBottom(() => {
const prev = timerRef.current
const curr = +Date.now()
if (!prev || curr - prev > THROTTLE_DELAY) {
events.trigger(REACH_BOTTOM_EVENT, pageRef.current)
timerRef.current = curr
} else {
console.log('wait...')
}
})
return null
}
复制代码
在 GitHub Pro 开发中,使用 Hooks 可以提升逻辑的复用,大大加快开发的速度,目前我尚未遇到过什么大坑,因此开发体验仍是不错的。
推荐资料:
以上我主要讲了如何写 Hooks,而编写以后的使用,能够自行看项目的代码
Repo: zenghongtu/GitHub-Pro