You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
3.4 KiB
TypeScript

import React, { useEffect, useState, useContext } from 'react'
import { search as SearchRepository } from '../api/repository'
import RepopositoryItem from './RepositoryItem'
import { RepositorySearchResultItem } from '../api/api'
import classes from './style/RepositoryList.module.css'
import { RepositorySearchCache } from '../utils/cache/RepositorySearch'
import RepositorySearchInput from './RepositorySearchInput'
import { RepositorySearchContext } from '../context/RepositorySearchContext'
interface RepositoryListProps {
/** 搜索关键词 */
keyword:string
/** 最多允许缓存多少页 */
max_cache_page:number
}
/**
* 默认每一页多少条记录
* https://docs.github.com/en/rest/reference/repos
*/
const DEFAULT_PER_PAGE = 30
export default function RepositoryList (props:RepositoryListProps) {
useContext(RepositorySearchContext)
/** 搜索关键词 */
const [keyword, setKeyword] = useState(props.keyword)
const cache = RepositorySearchCache(keyword, props.max_cache_page)
/** 当前页 */
const [current_page, setCurrentPage] = useState(1)
/** 总页码 */
const [total_page, setTotalPage] = useState(0)
/** 接口加载中 */
const [loading, setLoading] = useState(false)
const [list, setList] = useState<RepositorySearchResultItem[]>([])
/**
* 调用搜索接口
* @param {string} keyword 搜索关键词
* @param {number} page 页码
* @returns {Promise<void>}
*/
async function search (keyword:string, page:number):Promise<void> {
setLoading(true)
const cache_list = cache.read(page)
let _total_page = 0
// 有缓存
if (cache_list) {
setList(cache_list)
_total_page = cache.getTotalPage()
} else {
// 没有缓存,调用接口
try {
/* eslint-disable */
var result = await SearchRepository(keyword, page)
} catch (err) {
console.log('fetch',err);
alert(err.message)
setLoading(false)
return
}
_total_page = Math.ceil(result.total_count / DEFAULT_PER_PAGE)
setList(result.items)
cache.add(page,result.items)
cache.updateTotalPage(_total_page)
}
setTotalPage(_total_page)
setCurrentPage(page)
setLoading(false)
}
useEffect(() => {
search(keyword,1)
}, [])
function onClickPrev(){
search(keyword,current_page-1)
}
function onClickNext(){
search(keyword,current_page+1)
}
return (
<RepositorySearchContext.Provider value={{search,setKeyword,keyword,loading}}>
<div className={classes.wrapper}>
<RepositorySearchInput />
<div className={classes['list-wrapper']}>
<ul className={classes.list}>
{
list.map(item => <RepopositoryItem key={item.id} name={item.name} star_count={item.stargazers_count} fork_count={item.forks_count} />)
}
</ul>
{
list.length===0 && <span></span>
}
{
loading && <div className={classes.loading}></div>
}
</div>
<div className="action-bar">
<button disabled={loading || current_page<=1} onClick={onClickPrev}></button>
<button disabled={loading || current_page>=total_page} onClick={onClickNext}></button>
<span> {current_page} / {total_page}</span>
</div>
</div>
</RepositorySearchContext.Provider>
)
}