添加搜索框

This commit is contained in:
周炽键 2021-07-27 16:01:18 +08:00
parent 7ad342217e
commit e8317fd749
27 changed files with 90 additions and 8 deletions

5
.eslintrc.js Normal file → Executable file
View File

@ -23,5 +23,10 @@ module.exports = {
camelcase: 'off', camelcase: 'off',
'no-unused-vars': 'warn', 'no-unused-vars': 'warn',
'no-use-before-define': 'off' 'no-use-before-define': 'off'
},
settings: {
react: {
version: '17.0.0'
}
} }
} }

0
.gitignore vendored Normal file → Executable file
View File

13
.vscode/settings.json vendored Normal file → Executable file
View File

@ -1,4 +1,15 @@
{ {
"editor.defaultFormatter": "dbaeumer.vscode-eslint", "editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true "editor.formatOnSave": true,
"editor.tabSize": 2,
"eslint.trace.server": "verbose",
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"html",
"vue",
],
"eslint.format.enable": true
} }

0
README.md Normal file → Executable file
View File

0
deploy Normal file → Executable file
View File

0
index.html Normal file → Executable file
View File

0
package-lock.json generated Normal file → Executable file
View File

0
package.json Normal file → Executable file
View File

0
src/App.css Normal file → Executable file
View File

0
src/App.tsx Normal file → Executable file
View File

0
src/api/api.d.ts vendored Normal file → Executable file
View File

0
src/api/repository.ts Normal file → Executable file
View File

0
src/components/RepositoryItem.tsx Normal file → Executable file
View File

26
src/components/RepositoryList.tsx Normal file → Executable file
View File

@ -1,9 +1,11 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState, useContext } from 'react'
import { search as SearchRepository } from '../api/repository' import { search as SearchRepository } from '../api/repository'
import RepopositoryItem from './RepositoryItem' import RepopositoryItem from './RepositoryItem'
import { RepositorySearchResultItem } from '../api/api' import { RepositorySearchResultItem } from '../api/api'
import classes from './style/RepositoryList.module.css' import classes from './style/RepositoryList.module.css'
import { RepositorySearchCache } from '../utils/cache/RepositorySearch' import { RepositorySearchCache } from '../utils/cache/RepositorySearch'
import RepositorySearchInput from './RepositorySearchInput'
import { RepositorySearchContext } from '../context/RepositorySearchContext'
interface RepositoryListProps { interface RepositoryListProps {
@ -21,7 +23,12 @@ interface RepositoryListProps {
const DEFAULT_PER_PAGE = 30 const DEFAULT_PER_PAGE = 30
export default function RepositoryList (props:RepositoryListProps) { export default function RepositoryList (props:RepositoryListProps) {
const cache = RepositorySearchCache(props.keyword, props.max_cache_page) useContext(RepositorySearchContext)
/** 搜索关键词 */
const [keyword, setKeyword] = useState(props.keyword)
const cache = RepositorySearchCache(keyword, props.max_cache_page)
/** 当前页 */ /** 当前页 */
const [current_page, setCurrentPage] = useState(1) const [current_page, setCurrentPage] = useState(1)
@ -36,10 +43,11 @@ export default function RepositoryList (props:RepositoryListProps) {
/** /**
* *
* @param {string} keyword
* @param {number} page * @param {number} page
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async function search (page:number):Promise<void> { async function search (keyword:string, page:number):Promise<void> {
setLoading(true) setLoading(true)
const cache_list = cache.read(page) const cache_list = cache.read(page)
@ -54,7 +62,7 @@ export default function RepositoryList (props:RepositoryListProps) {
// 没有缓存,调用接口 // 没有缓存,调用接口
try { try {
/* eslint-disable */ /* eslint-disable */
var result = await SearchRepository(props.keyword, page) var result = await SearchRepository(keyword, page)
} catch (err) { } catch (err) {
console.log('fetch',err); console.log('fetch',err);
@ -80,20 +88,23 @@ export default function RepositoryList (props:RepositoryListProps) {
} }
useEffect(() => { useEffect(() => {
search(1) search(keyword,1)
}, []) }, [])
function onClickPrev(){ function onClickPrev(){
search(current_page-1) search(keyword,current_page-1)
} }
function onClickNext(){ function onClickNext(){
search(current_page+1) search(keyword,current_page+1)
} }
return ( return (
<RepositorySearchContext.Provider value={{search,setKeyword,keyword,loading}}>
<div className={classes.wrapper}> <div className={classes.wrapper}>
<RepositorySearchInput />
<div className={classes['list-wrapper']}> <div className={classes['list-wrapper']}>
<ul className={classes.list}> <ul className={classes.list}>
{ {
list.map(item => <RepopositoryItem key={item.id} name={item.name} star_count={item.stargazers_count} fork_count={item.forks_count} />) list.map(item => <RepopositoryItem key={item.id} name={item.name} star_count={item.stargazers_count} fork_count={item.forks_count} />)
@ -114,5 +125,6 @@ export default function RepositoryList (props:RepositoryListProps) {
</div> </div>
</div> </div>
</RepositorySearchContext.Provider>
) )
} }

View File

@ -0,0 +1,31 @@
import React, { useContext } from 'react'
import { RepositorySearchContext } from '../context/RepositorySearchContext'
export default function RepositorySearchInput () {
const context = useContext(RepositorySearchContext)
return (
<div>
<label htmlFor="keyword-input">
<input type="text" id="keyword-input"
value={context.keyword}
onChange={({ target }) => {
context.setKeyword(target.value)
}}
onKeyDown={evt => {
const value = (evt.target as HTMLInputElement).value
if (evt.key.toLocaleLowerCase() === 'enter') {
context.setKeyword(value)
context.search(value, 1)
}
}}
/>
</label>
<button onClick={() => {
context.search(context.keyword, 1)
}} disabled={context.loading}></button>
</div>
)
}

0
src/components/style/RepositoryList.module.css Normal file → Executable file
View File

View File

@ -0,0 +1,23 @@
import React from 'react'
export const RepositorySearchContext = React.createContext({
/**
*
* @param {string} keyword
* @param {number} page
*/
search (keyword:string, page:number) {},
/**
*
* @param {string} keyword
*/
setKeyword (keyword:string) {},
/** 搜索关键词 */
keyword: '',
/** 接口调用中 */
loading: false
})

0
src/favicon.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

0
src/index.css Normal file → Executable file
View File

0
src/logo.svg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

0
src/main.tsx Normal file → Executable file
View File

0
src/utils/cache/RepositorySearch.ts vendored Normal file → Executable file
View File

0
src/vite-env.d.ts vendored Normal file → Executable file
View File

0
start.sh Normal file → Executable file
View File

0
tsconfig.json Normal file → Executable file
View File

0
vite.config.ts Normal file → Executable file
View File

0
yarn.lock Normal file → Executable file
View File