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.