diff --git a/package.json b/package.json index 38dc9f71..ecfa6bcd 100644 --- a/package.json +++ b/package.json @@ -32,11 +32,11 @@ "prettier": "^2.2.1", "react": "^17.0.1", "react-app-polyfill": "^2.0.0", - "react-cookie": "^4.0.3", "react-dom": "^17.0.1", "react-hotkeys-hook": "^3.0.3", "react-scripts": "4.0.1", "react-timer-hook": "^2.0.7", + "react-use": "^17.1.0", "source-map-explorer": "^2.5.2", "typescript": "^4.0.3", "use-sound": "^2.0.1", diff --git a/src/index.tsx b/src/index.tsx index 0fc45ea7..8691c71e 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,17 +4,14 @@ import './index.css' import Typing from './pages/Typing' import './icon' import reportWebVitals from './reportWebVitals' -import { CookiesProvider } from 'react-cookie' import 'react-app-polyfill/stable' import { AppSettingsProvider } from 'components/AppSettings' ReactDOM.render( - - - - - + + + , document.getElementById('root'), ) diff --git a/src/pages/Typing/DictSwitcher/index.tsx b/src/pages/Typing/DictSwitcher/index.tsx new file mode 100644 index 00000000..2abfefb9 --- /dev/null +++ b/src/pages/Typing/DictSwitcher/index.tsx @@ -0,0 +1,52 @@ +import { WordListState, dictList } from '../hooks/useWordList' +import _ from 'lodash' + +export type DictSwitcherPropsType = { + dictName: string + chapter: number + chapterListLength: number + changeDict: any + changeChapter: any +} + +const DictSwitcher: React.FC = ({ dictName, chapter, chapterListLength, changeDict, changeChapter }) => { + return ( +
+
+ +
+ +
+ +
+
+ ) +} + +export default DictSwitcher diff --git a/src/pages/Typing/Switcher/index.tsx b/src/pages/Typing/Switcher/index.tsx index 3272c559..3a9e0153 100644 --- a/src/pages/Typing/Switcher/index.tsx +++ b/src/pages/Typing/Switcher/index.tsx @@ -1,6 +1,6 @@ import React, { Dispatch, useEffect } from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { switcherStateType, switcherDispatchType } from './useSwitcherState' +import { switcherStateType, switcherDispatchType } from '../hooks/useSwitcherState' import { useHotkeys } from 'react-hotkeys-hook' export type SwitcherPropsType = { diff --git a/src/pages/Typing/Switcher/useSwitcherState.ts b/src/pages/Typing/hooks/useSwitcherState.ts similarity index 100% rename from src/pages/Typing/Switcher/useSwitcherState.ts rename to src/pages/Typing/hooks/useSwitcherState.ts diff --git a/src/pages/Typing/hooks/useWordList.ts b/src/pages/Typing/hooks/useWordList.ts new file mode 100644 index 00000000..262fc7ad --- /dev/null +++ b/src/pages/Typing/hooks/useWordList.ts @@ -0,0 +1,89 @@ +import { useState, useCallback } from 'react' +import cet4 from 'assets/CET4_N.json' + +export const dictList: any = { + cet4: ['CET-4', ''], + cet6: ['CET-6', './dicts/CET6_N.json'], + gmat: ['GMAT', './dicts/GMAT_N.json'], + gre: ['GRE', './dicts/GRE_N.json'], + ielts: ['IELTS', './dicts/IELTS_N.json'], + kaoyan: ['考研', './dicts/KaoYan_N.json'], + level4: ['专四', './dicts/Level4_N.json'], + level8: ['专八', './dicts/Level8_N.json'], + sat: ['SAT', './dicts/SAT_N.json'], + toefl: ['TOEFL', './dicts/TOEFL_N.json'], + coder: ['Coder Dict', './dicts/it-words.json'], + jsArray: ['js-array', './dicts/js-array.json'], + jsDate: ['js-date', './dicts/js-date.json'], + jsGlobal: ['js-global', './dicts/js-global.json'], + jsMapSet: ['js-map-set', './dicts/js-map-set.json'], + jsMath: ['js-math', './dicts/js-math.json'], + jsNumber: ['js-number', './dicts/js-number.json'], + jsObject: ['js-object', './dicts/js-object.json'], + jsPromise: ['js-promise', './dicts/js-promise.json'], + jsString: ['js-string', './dicts/js-string.json'], +} + +export type WordType = { + name: string + trans: string[] + usphone: string + ukphone: string +} + +export type WordListState = { + dictName: string + chapter: number + chapterListLength: number +} +export type wordListDispatchType = (type: string, payload?: any, callback?: any) => void + +export const useWordList = ( + InputchapterLength: number, +): [dictName: string, chapter: number, chapterListLength: number, wordList: WordType[], dispatch: wordListDispatchType] => { + const [chapterLength, setChapterLength] = useState(InputchapterLength) + const [dictName, setDictName] = useState('cet4') + const [chapter, setChapter] = useState(0) + const [dict, setDict] = useState(cet4) + const [wordList, setWordList] = useState(dict.slice(chapter * chapterLength, (chapter + 1) * chapterLength)) + const [chapterListLength, setChapterListLength] = useState(Math.ceil(cet4.length / chapterLength)) + + const dispatch: wordListDispatchType = useCallback( + (type, payload, callback) => { + switch (type) { + case 'setDictName': + setDictName(payload) + + if (payload === 'cet4') { + const newDict = cet4 + setDict(newDict) + setWordList(newDict.slice(0 * chapterLength, (0 + 1) * chapterLength)) + setChapterListLength(Math.ceil(newDict.length / chapterLength)) + if (callback !== undefined) { + callback() + } + } else { + fetch(dictList[payload][1]) + .then((response) => response.json()) + .then((data) => { + const newDict = data + setDict(newDict) + setWordList(newDict.slice(0 * chapterLength, (0 + 1) * chapterLength)) + setChapterListLength(Math.ceil(newDict.length / chapterLength)) + if (callback !== undefined) { + callback() + } + }) + } + break + case 'setChapter': + setChapter(payload) + setWordList(dict.slice(payload * chapterLength, (payload + 1) * chapterLength)) + break + } + }, + [chapterLength, dict], + ) + + return [dictName, chapter, chapterListLength, wordList, dispatch] +} diff --git a/src/pages/Typing/index.tsx b/src/pages/Typing/index.tsx index ceac5ac0..57501ab2 100644 --- a/src/pages/Typing/index.tsx +++ b/src/pages/Typing/index.tsx @@ -12,42 +12,16 @@ import Phonetic from 'components/Phonetic' import { isLegal } from 'utils/utils' import { useHotkeys } from 'react-hotkeys-hook' import { useModals } from 'utils/hooks' -import { useCookies } from 'react-cookie' -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import useSwitcherState from './Switcher/useSwitcherState' -import { useAppSettings } from 'components/AppSettings' +import useSwitcherState from './hooks/useSwitcherState' import Switcher from './Switcher' +import DictSwitcher from './DictSwitcher' +import { dictList, useWordList } from './hooks/useWordList' +import { useLocalStorage } from 'react-use' -import cet4 from 'assets/CET4_N.json' - -const dicts: any = { - cet4: ['CET-4', ''], - cet6: ['CET-6', './dicts/CET6_N.json'], - gmat: ['GMAT', './dicts/GMAT_N.json'], - gre: ['GRE', './dicts/GRE_N.json'], - ielts: ['IELTS', './dicts/IELTS_N.json'], - kaoyan: ['考研', './dicts/KaoYan_N.json'], - level4: ['专四', './dicts/Level4_N.json'], - level8: ['专八', './dicts/Level8_N.json'], - sat: ['SAT', './dicts/SAT_N.json'], - toefl: ['TOEFL', './dicts/TOEFL_N.json'], - coder: ['Coder Dict', './dicts/it-words.json'], - jsArray: ['js-array', './dicts/js-array.json'], - jsDate: ['js-date', './dicts/js-date.json'], - jsGlobal: ['js-global', './dicts/js-global.json'], - jsMapSet: ['js-map-set', './dicts/js-map-set.json'], - jsMath: ['js-math', './dicts/js-math.json'], - jsNumber: ['js-number', './dicts/js-number.json'], - jsObject: ['js-object', './dicts/js-object.json'], - jsPromise: ['js-promise', './dicts/js-promise.json'], - jsString: ['js-string', './dicts/js-string.json'], -} - -type WordType = { - name: string - trans: string[] - usphone: string - ukphone: string +type localStorage = { + dictName: string + chapter: number + order: number } const App: React.FC = () => { @@ -55,20 +29,14 @@ const App: React.FC = () => { const [order, setOrder] = useState(0) const [isLoading, setIsLoading] = useState(false) - const [dictName, setDictName] = useState('cet4') - const [dict, setDict] = useState>(cet4) const [inputCount, setInputCount] = useState(0) const [correctCount, setCorrectCount] = useState(0) const [isStart, setIsStart] = useState(false) - const [chapterListLength, setChapterListLength] = useState(10) - const [chapter, setChapter] = useState(0) - const [wordList, setWordList] = useState>(dict.slice(chapter * chapterLength, (chapter + 1) * chapterLength)) - - const [cookies, setCookies] = useCookies() - + const [localStorage, setLocalStorage] = useLocalStorage('Dict') const [switcherState, switcherStateDispatch] = useSwitcherState({ wordVisible: true, phonetic: false }) + const [dictName, chapter, chapterListLength, wordList, wordListDispatch] = useWordList(chapterLength) const { modalState, @@ -99,20 +67,21 @@ const App: React.FC = () => { useEffect(() => { // 首次加载时,读取 cookies - const cookieDict = cookies.dict - const cookieChapter = parseInt(cookies.chapter) - const cookieOrder = parseInt(cookies.order) - if (cookieDict && cookieChapter) { + console.log(localStorage) + if (localStorage) { + const cookieDict = localStorage.dictName + const cookieChapter = localStorage.chapter + const cookieOrder = localStorage.order setModalMessage( '提示', - `您上次练习到字典 ${dicts[cookieDict][0]} 章节 ${cookieChapter + 1} 第${cookieOrder + 1}个单词 ,是否继续?`, + `您上次练习到字典 ${dictList[cookieDict][0]} 章节 ${cookieChapter + 1} 第${cookieOrder + 1}个单词 ,是否继续?`, '继续上次练习', '从头开始', ) setModalHandler( () => { - changeDict(cookieDict, cookieChapter) setOrder(cookieOrder) + changeDict(cookieDict, cookieChapter) setModalState(false) }, () => { @@ -149,24 +118,17 @@ const App: React.FC = () => { }, [isStart]) useEffect(() => { - setChapterListLength(Math.ceil(dict.length / chapterLength)) - }, [dict]) - - useEffect(() => { - setWordList(dict.slice(chapter * chapterLength, (chapter + 1) * chapterLength)) - setOrder(0) - }, [dict, chapter]) - - useEffect(() => { - setCookies('chapter', chapter, { path: '/' }) - setCookies('dict', dictName, { path: '/' }) - setCookies('order', order, { path: '/' }) - }, [dictName, chapter, order, setCookies]) + setLocalStorage({ + dictName, + chapter, + order: order, + }) + }, [dictName, chapter, order, setLocalStorage]) const modalHandlerGenerator = (chapter: number, order: number, modalState: boolean) => { return () => { setOrder(order) - setChapter(chapter) + wordListDispatch('setChapter', chapter) setModalState(modalState) } } @@ -193,28 +155,31 @@ const App: React.FC = () => { } } else { setOrder((order) => order + 1) - setCorrectCount((count) => count + dict[order].name.trim().length) + setCorrectCount((count) => count + wordList[order].name.trim().length) } } - const changeDict = (dictName: string, chaper: number = 0) => { - setIsLoading(true) - setDictName(dictName) + const changeDict = useCallback( + (dictName: string, chapter?: number) => { + setOrder(0) + setIsLoading(true) + wordListDispatch('setDictName', dictName, () => { + setIsLoading(false) + if (chapter !== undefined) { + wordListDispatch('setChapter', chapter) + } + }) + }, + [wordListDispatch], + ) - if (dictName === 'cet4') { - setDict(cet4) - setChapter(chaper) - setIsLoading(false) - } else { - fetch(dicts[dictName][1]) - .then((response) => response.json()) - .then((data) => { - setDict(data) - setChapter(chaper) - setIsLoading(false) - }) - } - } + const changeChapter = useCallback( + (chapter: number) => { + setOrder(0) + wordListDispatch('setChapter', chapter) + }, + [wordListDispatch], + ) return ( <> @@ -235,39 +200,13 @@ const App: React.FC = () => { {isLoading && }
-
- -
- -
- -
+