前段時間學習了React、Typescript,因此兩個一塊兒用試試; 有點遺憾的是Redux還沒學,後續學了Redux後纔算完整。。。沒辦法,三分鐘熱度的我還在學flutter啊。。。javascript
說一下調接口的問題,最近包括上一份工做都遇到過,後端接口收不到參數。。。搞半天,結果是由於他們是從URL獲取的請求參數,不管請求方式是否GET,,,因此溝通仍是很重要的,若是後端大佬接口測試經過(postman/swagger等),可是頁面上調用仍是接收不到參數,,,就要去看他們接收參數的方式了,看他們測試的請求request URL就知道了css
代碼:react-tsjava
提早學習TypeScript、React相關用法node
npm install -g create-react-app
複製代碼
會自動安裝一些typescript相關的東西,還有react的typescript版本,一些庫的聲明等
react
create-react-app my-app --scripts-version=react-scripts-ts
複製代碼
注意修改配置須要重啓項目纔會生效git
tslint.json:github
{
"extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
"linterOptions": {
"exclude": [
"config/**/*.js",
"node_modules/**/*.ts",
"coverage/lcov-report/*.js"
]
},
"rules": {
"no-debugger": false,
"no-console": false,
//聲明interface是否須要首字母爲大寫的I
"interface-name": false,
//須要按字母順序引入模塊
"ordered-imports": false,
"object-literal-sort-keys": false,
// jsx中匿名函數
"jsx-no-lambda": false
},
"jsRules": {
"no-debugger": false,
"no-console": false,
//聲明interface是否須要首字母爲大寫的I
"interface-name": false,
//須要按字母順序引入模塊
"ordered-imports": false,
"object-literal-sort-keys": false
}
}
複製代碼
react好像沒有命名式路由,只能經過path去跳轉,也沒有路由元信息meta;有時間看下有沒有其餘解決方案;
官網文檔:react-routerweb
<Route>
有 children/render/component 三個屬性決定當前路由渲染什麼,exact 爲true表示精確匹配路由,不然模糊匹配;<Route component>
,<Route render>
優先級比<Route children>
高
<Route component>
: 直接放組件<Route render>
: 直接在這裏寫 JSX<Route children>
: 與render
相似;能夠根據匹配(match
)的url渲染,,, 這個暫時還不知道具體使用場景(多是nav
菜單欄,根據路由決定激活狀態之類吧)<Switch>
能夠看做是單選框的做用,只匹配第一個符合條件的路由; 路由位置<Route>
通常精確路由放前面,模糊路由放後面typescript
// src/router.tsx
import * as React from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import Loadable from '@loadable/component';
import PageRoutes from './routes/index';
// 使用 import { lazy } from '@loadable/component';
// lazy()會有警告,跟React.lazy()同樣的警告
const App = Loadable(() => import('./App'));
const ErrComp = Loadable(() => import('./views/ErrComp/index'));
// 生成 路由集合
const GetRoutes = () => {
const AppRoute =
<Route
key='app'
path='/'
exact={true}
component={App}
/>;
const ErrRoute =
<Route
key='err404'
exact={true}
path='/err404'
component={ErrComp}
/>;
const NoMatchRoute =
<Route
key='no-match'
component={ErrComp}
/>;
const routes = [AppRoute, ...PageRoutes, ErrRoute, NoMatchRoute];
return (
<Switch>
{routes.map(route => route)}
</Switch>
);
}
export default function Routes() {
return (
<HashRouter>
<GetRoutes />
</HashRouter>
);
}
複製代碼
// src/routes/hello.tsx
import { Route } from 'react-router-dom';
import * as React from 'react';
import Loadable from '@loadable/component';
// 有子路由的話暫時這樣處理吧,精確的放前面,模糊的放後面
export default [
<Route
key="hello"
exact={true}
path="/hello"
component={Loadable(() => import('../views/Hello/index'))}
/>,
<Route
key="hello_child1"
exact={true}
path="/hello/child1"
component={Loadable(() => import('../views/Hello/hello_child1'))}
/>,
<Route
key="hello_id"
exact={true}
path="/hello/:id"
component={Loadable(() => import('../views/Hello/hello_id'))}
/>
]
複製代碼
曾經我在另外一個React的項目寫的時候是支持 import(`../views/${name}`) 這種寫法的。。。不知爲什麼在這裏(React + TypeScript)不行npm
React.lazy(() => import(component));
複製代碼
npm i @loadable/component
複製代碼
而後在項目根目錄新建一個文件 loadable.d.ts或者統一一個文件.d.ts中寫, (若是不提示找不到模塊,就不須要本身新建了) 寫入聲明 declare module '@loadable/component';
使用:
import Loadable from '@loadable/component';
const App = Loadable(() => import('./App'));
正常使用,沒有問題!!!
import { lazy } from '@loadable/component';
const App = lazy(() => import('./App'));
能夠用的,可是會有警告(跟使用React.lazy()的問題同樣):Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it. in Suspense
// src/routes/index.tsx
import hello from './hello';
export default [
...hello
]
複製代碼
- 路由組件能夠直接獲取這些屬性(history,location,match等),而非路由組件就必須經過withRouter修飾後才能獲取這些屬性了
- 目的就是讓被修飾的組件能夠從props屬性中獲取history,location,match等方法
有兩點要注意:
withRouter<thisProps>(Hello as any)
兩者的區別也就是 RouteComponentProps的合成 方式不一樣而已
寫法一:
import * as React from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
export interface Props extends RouteComponentProps<any> {
name?: string;
}
class Hello extends React.Component<Props, {}> {
constructor(props: Props) {
super(props);
}
// 方法名 須要添加 public/ private / protected
public render() {...}
}
export default withRouter<Props>(Hello as any);
複製代碼
寫法二:
import * as React from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
export interface Props {
name?: string;
}
type thisProps = Props & RouteComponentProps;
class Hello extends React.Component<thisProps, {}> {
constructor(props: thisProps) {
super(props);
}
// 方法名 須要添加 public/ private / protected
public render() {...}
}
export default withRouter<thisProps>(Hello as any);
複製代碼
// src/index.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Routes from './router';
import './index.css';
// import registerServiceWorker from './registerServiceWorker';
const Loading = () => <div>loading...</div>;
ReactDOM.render(
<React.Suspense fallback={Loading}>
<Routes />
</React.Suspense>,
document.getElementById('root') as HTMLElement
);
// registerServiceWorker();
複製代碼
// src/App.tsx
import * as React from 'react';
import './App.css';
// import logo from './logo.svg';
interface Props {
[prop: string]: any
}
class App extends React.Component<Props, {}> {
constructor(props: Props) {
super(props);
this.state = {};
}
public render() {
const { history, location } = this.props;
return (
<div style={{display: location.pathname === '/' ? '' : 'none'}}> <p>這是app</p> <p> <a href="javascript:;" onClick={() => history.push('/hello')}> go hello </a> </p> <hr /> </div>
);
}
}
export default App;
複製代碼
// src/components/Hello.tsx
import * as React from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
export interface Props {
from?: string;
}
export interface States {
times: number;
}
type thisProps = Props & RouteComponentProps;
class Hello extends React.Component<thisProps, States> {
constructor(props: thisProps) {
super(props);
this.state = {
times: 0
}
this.bclick = this.bclick.bind(this);
}
public bclick() {
this.setState({
times: this.state.times+1
})
}
// 方法名 須要添加 public/ private / protected
public render() {
const { from } = this.props;
const { times } = this.state;
return (
<div> <h4>Hello { from }</h4> 點擊了 {times} <p> <button onClick={this.bclick}>點擊</button> </p> </div>
)
}
}
export default withRouter<thisProps>(Hello as any);
複製代碼