經過靜態類型檢測能夠儘早檢測出程序中隱藏的的邏輯錯誤,對於JavaScript動態的弱類型語言,雖然靈活性高,可是對於初學者來講,若是不熟悉JavaScript內部的語言機制,很容易形成隱藏的事故。可是經過TypeScript的靜態類型檢測能夠規避這些問題,由於其可以約束變量產生的類型。結合IDE編輯器能夠推導變量對應的類型以及內部的結構,提升代碼的健壯性和可維護性。css
類型系統可以強化規範編程,TypeScript提供定義接口。在開發大型複雜的應用軟件時十分重要,一個系統模塊能夠抽象的看作一個TypeScript定義的接口。讓設計脫離實現,最終體現出一種 IDL(接口定義語言,Interface Define Language),讓程序設計迴歸本質。前端
TypeScript能夠自動根據類型標註生成文檔,對於簡單的功能實現都不須要編寫註釋。react
先要明白 mobx 和 redux 的定位是不一樣的。redux 管理的是 (STORE -> VIEW -> ACTION) 的整個閉環,而 mobx 只關心 STORE -> VIEW 的部分。webpack
Redux優缺點:git
Mobx優缺點:github
SO: 前端數據流不太複雜的狀況,使用 Mobx,由於更加清晰,也便於維護;若是前端數據流極度複雜,建議謹慎使用 Redux,經過中間件減緩巨大業務複雜度web
npm i -g create-react-app create-react-app tinylog-ui --scripts-version=react-scripts-ts cd tinylog-ui/ npm start npm run eject
TPS: 最後一個命令使用eject將全部內建的配置暴露出來typescript
經過create-react-app能夠很方便地對整個項目完成環境初始化,若是願意折騰TypeScript和webpack的環境能夠試試,這裏忽略webpack和TypeScript的環境搭建過程,而是使用create-react-app來實現環境搭建。npm
單頁應用怎麼能夠沒有前端路由呢,因此咱們要加入React-Rotuer, 這裏使用的React-Router的版本是v4.2.0編程
對於React-Router,這裏使用到的模塊有Router, Route, Switch
React Router 是創建在 history 之上的。 簡而言之,一個 history 知道如何去監聽瀏覽器地址欄的變化, 並解析這個 URL 轉化爲 location 對象, 而後 router 使用它匹配到路由,最後正確地渲染對應的組件。
代碼以下:
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Router, Route, Switch } from 'react-router'; import { createBrowserHistory } from 'history'; import registerServiceWorker from './registerServiceWorker'; import { Root } from './containers/Root'; import './index.css'; import Container from './containers/Container'; import SignIn from './containers/Auth/signIn'; import SignUp from './containers/Auth/signUp'; const history = createBrowserHistory(); ReactDOM.render( <Root> <Router history={history}> <Switch> <Route path="/signIn" component={SignIn} /> <Route path="/signUp" component={SignUp} /> <Route path="/" component={Container} /> </Switch> </Router> </Root>, document.getElementById('root') as HTMLElement ); registerServiceWorker();
這裏描述一寫Container這個組件的編寫
import * as React from 'react'; import Header from '../../layout/Header'; import { IAuth } from '../../interfaces'; import { Route, Switch } from 'react-router'; import App from '../App'; import Website from '../Website'; // 這部分是坑點,一開始不知道配置,後發現react-rotuer的4.0版本下須要配置prop的接口 interface Container extends RouteComponentProps<{}> { } class Container extends React.Component<Container, {}> { render () { return ( <div> <Header {...this.props} /> <Switch> <Route path="/website" component={Website}/> <Route path="/" component={App}/> </Switch> </div> ) } } export default Container;
這樣,當咱們訪問url爲'/'的時候,默認會進入Container,其中Container裏面是一層子頁面,會匹配url,若是url爲'/website', 則進入Website頁面,若爲'/',則進入App頁面。
具體關於React-Router的使用請閱讀React-Router文檔
npm i mobx react-mobx mobx-react-router -S
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Router, Route, Switch } from 'react-router'; import { createBrowserHistory } from 'history'; import { useStrict } from 'mobx'; import { Provider } from 'mobx-react'; import { RouterStore, syncHistoryWithStore } from 'mobx-react-router'; // 定義須要使用到的store來進行數據狀態的管理 import { TokenStore, AuthStore, HostStore, OverViewStore, AssetsStore, CommonDataStore, PageStore, RealTimeStore } from './stores'; import registerServiceWorker from './registerServiceWorker'; import { Root } from './containers/Root'; import './index.css'; import Container from './containers/Container'; import SignIn from './containers/Auth/signIn'; import SignUp from './containers/Auth/signUp'; // 引入Echarts import './macarons'; import 'echarts/map/js/world'; // 開啓mobx的嚴格模式,規範數據修改操做只能在action中進行 useStrict(true); const browserHistory = createBrowserHistory(); const routerStore = new RouterStore(); // 同步路由與mobx的數據狀態 const history = syncHistoryWithStore(browserHistory, routerStore); const rootStore = { token: new TokenStore(), auth: new AuthStore(), host: new HostStore(), overview: new OverViewStore(), assets: new AssetsStore(), commmon: new CommonDataStore(), page: new PageStore(), realtime: new RealTimeStore(), router: routerStore }; ReactDOM.render( <Provider {...rootStore}> <Root> <Router history={history}> <Switch> <Route path="/signIn" component={SignIn} /> <Route path="/signUp" component={SignUp} /> <Route path="/" component={Container} /> </Switch> </Router> </Root> </Provider>, document.getElementById('root') as HTMLElement ); registerServiceWorker();
import * as React from 'react'; import Header from '../../layout/Header'; import { IAuth } from '../../interfaces'; import { Route, Switch } from 'react-router'; // 使用inject和observer來進行數據監聽和數據依賴聲明 import { inject, observer } from 'mobx-react'; import App from '../App'; import Website from '../Website'; interface Container extends IAuth { } @inject('router', 'auth') @observer class Container extends React.Component<Container, {}> { render () { return ( <div> <Header {...this.props} /> <Switch> <Route path="/website" component={Website}/> <Route path="/" component={App}/> </Switch> </div> ) } } export default Container;
@observable 能夠在實例字段和屬性 getter 上使用。 對於對象的哪部分須要成爲可觀察的,@observable 提供了細粒度的控制。@inject 至關於Provider 的高階組件。能夠用來從 React 的context中挑選 store 做爲 prop 傳遞給目標組件
import { RouteComponentProps } from 'react-router'; import { RouterStore, AuthStore } from '../stores'; export interface IBase extends RouteComponentProps<{}> { router: RouterStore; } export interface IAuth extends IBase { auth: AuthStore; }
先看一下RouterStore:
import { History } from 'history'; import { RouterStore as BaseRouterStore, syncHistoryWithStore } from 'mobx-react-router'; // 路由狀態同步 class RouterStore extends BaseRouterStore { public history; constructor(history?: History) { super(); if (history) { this.history = syncHistoryWithStore(history, this); } } } export default RouterStore;
而後是AuthStore:
import { ISignIn, ISignUp } from './../interfaces/index'; import { observable, action } from 'mobx'; import api from '../api/auth'; import { IUser } from '../models'; // 登陸註冊狀態 class AuthStore { @observable token; @observable id; @observable email; constructor () { this.id = ''; this.token = ''; this.email = ''; } setLocalStorage ({ id, token, email }: IUser) { localStorage.setItem('id', id); localStorage.setItem('token', token); localStorage.setItem('email', email); } clearStorage () { localStorage.clear(); } @action async signIn (data: ISignIn) { try { const { data: res } = await api.signIn(data); this.id = res.data.id; this.token = res.data.token; this.email = res.data.email; this.setLocalStorage({ id: this.id, token: this.token, email: this.email }); return res; } catch (error) { return error; } } @action async signUp (data: ISignUp) { try { const { data: res } = await api.signUp(data); this.id = res.data.id; this.token = res.data.token; this.email = res.data.email; this.setLocalStorage({ id: this.id, token: this.token, email: this.email }); return res; } catch (error) { return error; } } @action signOut () { this.id = ''; this.token = ''; this.email = ''; this.clearStorage() } } export default AuthStore;
Auth是用於網站的登陸註冊事件以及對應的Token的數據狀態保存,登陸註冊事件的接口請求等操做。
具體的有關Mobx的用法請閱讀Mobx文檔
app ├── api 後端提供的接口數據請求 ├── components 編寫的可複用組件 ├── config 側邊欄以及導航欄配置 ├── constants 常量編寫 ├── interfaces 接口編寫 ├── layout 佈局外框 ├── stores mobx的數據狀態管理 ├── index.css 全局樣式 ├── index.tsx 頁面入口 ├── reset.css 瀏覽器重置樣式
本項目使用了Ant-Design來做爲依賴的組件庫,具體怎麼使用以及配置請參考Ant-Design
到這裏其實以及完成對React下TypeScript結合React-Router和Mobx的配置。具體的業務模塊如何編寫有興趣能夠參閱項目tinylog-ui
我的表達能力有限,沒法描述得太清晰,請見諒!