示例是使用 antd 组件库作测试的,有 react-router 和 redux 穿插,项目比较
基本效果如图
项目结构:
react-typescript-demo
node_modules
public
favicon.ico
index.html
manifest.json
src
pages
a.tsx
b.tsx
store
index.js
App.css
App.test.tsx
App.tsx
index.css
index.tsx
logo.svg
react-app-env.d.ts
serviceWorker.ts
.gitignore
package.json
README.md
tsconfig.json
yarn.lock
package.json
{
"name": "react-typescript-demo",
"version": "0.1.0",
"private": true,
"dependencies": {
"@types/jest": "24.0.13",
"@types/node": "12.0.1",
"@types/react": "16.8.17",
"@types/react-dom": "16.8.4", // @types/react 和 @types/react-dom 是在 create-react-app 创建项目时生成的
"antd": "^3.18.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-redux": "^7.0.3",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0",
"react-scripts": "3.0.1",
"redux": "^4.0.1",
"typescript": "3.4.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {"extends": "react-app"},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": { // typescript 版本的文件依赖
"@types/react": "^16.8.17",
"@types/react-redux": "^7.0.9",
"@types/react-router": "^5.0.0",
"@types/react-router-dom": "^4.3.3"
}
}
index.tsx 主文件
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// 引入 antd 相关
import {LocaleProvider} from 'antd';
import zhCN from 'antd/lib/locale-provider/zh_CN';
import 'antd/dist/antd.css';
import {BrowserRouter} from 'react-router-dom';
import {Provider} from "react-redux";
import store from './store';
// ReactDOM.render(<App />, document.getElementById('root'));
ReactDOM.render(<Provider store={store}>
<LocaleProvider locale={zhCN}>
<BrowserRouter>
<App/>
</BrowserRouter>
</LocaleProvider>
</Provider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
App.tsx
import React, {Component} from 'react';
import './App.css';
import {Switch, Route} from 'react-router';
import {NavLink} from 'react-router-dom';
import {Layout} from 'antd';
import A from './pages/a';
import B from './pages/b';
import {Dispatch} from 'redux';
import {connect} from "react-redux";
const {Header, Footer, Sider, Content} = Layout;
interface Props {
cName: string,
changeName?: any
}
interface State {name: string}
class App extends Component<Props> {// constructor(props: Props){// super(props);
// }
render() {console.log(this.props.cName);
return (
<Layout>
<Sider>
<ul>
<li><NavLink to="/a" activeClassName="selected">page a</NavLink></li>
<li><NavLink to="/b" activeClassName="selected">page b</NavLink></li>
</ul>
</Sider>
<Layout>
<Header>Header</Header>
<Content>
<Switch>
<Route exact path="/a" component={A}/>
<Route path="/b" component={B}/>
<Route component={A}/>
</Switch>
<p style={{fontSize: 24, color: '#f00'}}>{this.props.cName}</p>
</Content>
<Footer>Footer</Footer>
</Layout>
</Layout>
)
}
componentDidMount() {setTimeout(() => {
this.props.changeName({name: 'jack'});
}, 1500);
}
}
// 把 state 放到 props 里
function mapStateToProps(state: State) {
return {cName: state.name}
}
// 把方法放到 props 里
function mapDispatchToProps(dispatch: Dispatch) {
return {changeName: (payload: object)=>dispatch({type: 'CHANGE_NAME', payload: payload})
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
store/index.js
import {createStore} from 'redux';
function toDo(state, action) {state = state || {name: 'tom'};
switch (action.type) {
case 'CHANGE_NAME':
return {...state, ...action.payload};
default:
return state;
}
}
let store = createStore(toDo);
export default store;
page/a.tsx
import React, {Component} from 'react';
import {Button} from 'antd';
class A extends Component {render() {
return (
<div>
<Button type="primary">Primary</Button>
<Button>Default</Button>
<Button type="dashed">Dashed</Button>
<Button type="danger">Danger</Button>
<Button type="link">Link</Button>
</div>
)
}
}
export default A;
page/b.tsx
import React, {Component} from 'react';
import {Avatar} from 'antd';
class B extends Component {render() {
return (
<div>
<div>
<Avatar size={64} icon="user" />
<Avatar size="large" icon="user" />
<Avatar icon="user" />
<Avatar size="small" icon="user" />
</div>
<div>
<Avatar shape="square" size={64} icon="user" />
<Avatar shape="square" size="large" icon="user" />
<Avatar shape="square" icon="user" />
<Avatar shape="square" size="small" icon="user" />
</div>
</div>
);
}
}
export default B;