ts
卻無從下手, 學了 ts
想融入到 react
開發中卻找不到練手demo的新手, 一個 測試鼠標和鍵盤點擊速度的App
, 本項目雖然有不少類似版本, 可是不符合各類依賴的版本更替
,而且沒有 typescript
的實現版本, 因此崩崩以爲仍是有必要實現如下這個小東西, 給新手一些參考...... 具體效果以下圖: Ps: 這是一個測試鼠標點擊速度的 App,記錄 1 秒內用戶能最多點幾回。頂部的 Highest Record 紀錄最高速度;中間的是當前速度,給予即時反饋,讓用戶更有參與感;下方是供點擊的按鈕。
npm install -g typescript npm install --g dva-cli@next // 最新版本 dva腳手架, 目前爲 1.0.0-beta.4 npm install --save-dev @types/react @types/react-dom npm install --save-dev ts-loader tslint-react npm install --save antd npm install --save keymaster // 鍵盤事件依賴, 後面會用到
dva new 07-dva_calculator_count_example & cd 07-dva_...
具體相關配置詳見 崩崩 的第一篇文章: 連接描述
因爲 dva與umi 經過 umi-plugin-dva 插件相結合, 使用起來很是方便html
而咱們的項目路由則約定在
./src/pages
目錄下, 因此新建 example 文件夾./src/pages/example
接着測試咱們的路由, 在./src/pages/example
下新建page.tsx
(./src/pages/example/page.tsx
),node
在./src/pages/example
新建page.tsx
, 寫入測試的react
組件
import * as React from 'react'; export interface ICounterProps { }; const Counter: React.SFC<ICounterProps> = (): JSX.Element => { return ( <h1>This is example page.</h1> ); }; export default Counter;
接着, 命令行鍵入npm start
, 在Chrome
地址欄接上example
, 能夠看到結果了, 路由成功!
- 首先新建
./src/utils/delay.tsx
, 這是model中的延遲函數, 比較簡單
// 定義 Promise 接口 interface IDelayPromise { Promise: (resolve?: () => {}, reject?: () => {}) => void; }; const delay = (time: number): IDelayPromise => { return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, time); }); }; export default delay;
- 如今正式開始書寫咱們的
model
,model
是一個項目的靈魂,- 因此我放在
第一步
來作...... 新建./src/pages/example/models/counter.tsx
, 代碼以下:
import key from 'keymaster'; // 鍵盤相關事件 import delay from '../../../utils/delay'; // 延遲函數 export default { namespace: 'counter', state: { current: 0, // 即時顯示的數字 record: 0, // 最高紀錄 }, /* 回想咱們的需求 1. 鼠標點擊, 數字增長, 紀錄一秒內最高次數 2. 一秒後, 數字遞減, 變爲初始數字 而 reducers 是惟一能夠改變 state 的地方, 這個需求裏,咱們須要定義兩個 reducer, count/add 和 count/minus ,分別用於計數的增和減。要注意的是 count/add 時 record 的 邏輯,他只在有更高的記錄時纔會被記錄, 這個用一句 三元判斷便可 */ reducers: { add (state) { const newCurrent = state.current + 1; return { ...state, record: newCurrent > state.record ? newCurrent: state.record, current: newCurrent, }; }, minus (state) { const newCurrent = state.current - 1; return { ...state, current: newCurrent, }; }, }, /* 接着, 因爲咱們要實現, 延遲並返回初始狀態, 因此, 咱們在 effects 中定義 addRemote 方法 注: 這裏的 call, put, 是大佬封裝好的方法, 直接使用便可 call: 用於調用異步處理函數 put: 調用 reducers */ effects: { *addRemote ({ payload }, { call, put }) { yield put({ type: 'add' }); yield call({ delay, 1000 }); // delay 函數, yield put({ type: 'minus' }); }, }, /* 最後, 咱們能夠再加一點功能, 經過訂閱鍵盤來獲取鍵盤敲擊次數 固然, 按鍵也是隨意更改的, 經過 subscriptions */ subscriptions: { keyboardWather ({ dispatch }) { key('space', () => { dispatch({ type: 'addRemote' }); }); }, }, };
OK, 到這裏, 咱們的model
部分已經完成, 這是一個項目最重要的部分, 對相似put
,call
,subscriptions
這些api
不太熟悉的能夠看一下這裏: 連接描述
- 如今開始項目組件的編寫, 由於全部的狀態都被存到了
dva
中,- 因此書寫
簡單
而美觀
的函數組件(SFC)
是不二之選
./src/pages/example/page.tsx
,這是大的路由
組件, 裏面包含相似 Header
, Nav
, Footer
, 等相似的 容器組件
, 在其內寫入以下代碼:import * as React from 'react'; import Counter from './components/Counter'; // 導入 Counter 組件, 這是整個項目的容器 const styles: NodeRequire = require('./index.less'); // 整個項目的樣式文件, 等會兒會一一列出 export interface IAppProps {}; const App: React.SFC<IAppProps> = (): JSX.Element => { return ( <div className={styles['app-container']}> <div className={styles['app-content']}> <Counter /> </div> </div> ); }; export default App;
./src/pages/example/index.less
,寫入樣式.app-container {} .app-content { box-sizing: border-box; overflow: hidden; width: 400px; height: 400px; margin: 50px auto; border: 1px solid #ccc; box-shadow: 0 0 4px 4px #ddd; } .counterbox { display: flex; flex-direction: column; box-sizing: border-box; height: 100%; padding: 10px; } .counterbox .counter-show { flex: 1; line-height: 1.5; font-size: 20px; color: #666; } .counterbox .counter-currentcount { line-height: 100px; font-size: 30px; } .counterbox .counter-button { flex: 3; display: flex; justify-content: center; align-items: center; height: 100%; margin-top: 10px; }
./src/pages/example/components/Counter.tsx
, 這是整個項目的工做地import * as React from 'react'; import { connect } from 'dva'; // 將dva中的 state 轉化爲組件的 props import { Dispatch } from '../../../node_modules/redux'; // 類型限制, const styles: NodeRequire = require('../index.less'); import CounterButton from './CounterButton'; // 這是點擊的按鈕, 我將它分紅了一個單獨的組件, // 定義接口 export interface ICounterProps { current: number; // 即時數字 record?: number; // 最高紀錄 dispatch: Dispatch<{type: string, payload?: any}>; // tip: 這裏類型定義Dispatch, vscode 會自動幫我引入 Dispatch, 很智能 }; const Counter: React.SFC<ICounterProps> = (props: ICounterProps): JSX.Element => { const { current, record, dispatch } = props; // 按鈕點擊事件, 處理函數 const handleClick: React.ReactEventHandler<HTMLButtonElement> = (event: React.MouseEvent<HTMLButtonElement>): void => { console.log(event.currentTarget); // button Element dispatch({ type: 'counter/addRemote', // 觸發 action }); }; return ( <div className={styles['counterbox']}> <p className={styles['counter-show']}>The highest count is: { record }</p> <div className={styles['counter-currentcount']}> Current count is: { current } </div> <div className={styles['counter-button']}> <CounterButton onBtnClick={handleClick} /> </div> </div> ); }; // 將 state => props const mapStateToProps = (state): {current: number, record?: number} => { const { current, record } = state.counter; return { current, record, }; }; export default connect(mapStateToProps)(Counter);
Button按鈕
組件import * as React from 'react'; import { Button } from 'antd'; export interface ICounterButtonProps { onBtnClick: (event: React.MouseEvent<HTMLButtonElement>) => void; }; const CounterButton: React.SFC<ICounterButtonProps> = (props: ICounterButtonProps): JSX.Element => { return ( <Button type = "primary" onClick = {props.onBtnClick} > Please Click Me </Button> ); }; export default CounterButton;
保存, 刷新瀏覽器, 應該就OK啦
項目不難, 可是對於
新手
來講, 如何使用ts
進行類型定義
? ,以及懂得如何去梳理脈絡
, 我以爲是相當重要的.對代碼有不懂的同窗能夠
下方評論
,或者加扣: 1766083035, 深刻討論自學不易,
100% of the effort to change back to the tears of graduation.