在 Taro Hooks 出來 之後就一直想着體驗一波 Hooks 小程序開發,不過一直忙着補番 😌。最近補完了,就搞了起來,開發了 20 天左右(其實大部分時間都在改 UI😒),基本上是完成了,然後也上架了,遂跟大家分享一點心得 😈
可以先掃描體驗:
網絡不穩定的小夥伴看預覽:
在 GitHub Pro 的開發中,我寫了四個 hooks,來幫助我提高開發效率
- useRequest
- useRequestWithMore
- useReachBottomEvent
- usePullDownRefreshEvent
接下來就分析一下它們的作用
useRequest
作用同名字,用來進行網絡請求,傳入請求參數以及進行請求的函數,存儲數據,返回 [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
useRequestWithMore
這個鉤子是最複雜的一個,也是作用最大的一個函數。能夠在滾動條到底底部的時候,請求下一頁,加載更多的數據。
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]
}
是不是很完美,可惜不是這麼簡單。
Taro 中有個大坑就是在組件中無法使用如usePullDownRefresh
、useReachBottom
等鉤子。
所以就引出來一個大問題 -- 如何在組件中觸發這些操作呢。而且在 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
非常關鍵,用來對消息進行配對,防止說我這個頁面滾動,導致另外一個頁面也進行數據的請求。
usePullDownRefreshEvent
這個鉤子用來做當下拉刷時候發送刷新頁面的消息(在 page 內使用),而接受者就前面useRequestWithMore
了
function usePullDownRefreshEvent() {
const pageRef = useRef(getUniqueId())
usePullDownRefresh(() => {
events.trigger(PULL_DOWN_REFRESH_EVENT, pageRef.current)
})
return null
}
useReachBottomEvent
這個鉤子用來做當頁面滾動到底部時候發送獲取數據的消息(在 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