乐趣区

reacttypescriptreduxrouter入门

示例是使用 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;
退出移动版