討論幾個問題,react 組件的聲明?react 高階組件的聲明和使用?class組件中 props 和 state 的使用?...javascript
jsx
語法的文件都須要以tsx
後綴命名Component<P, S>
泛型參數聲明,來代替PropTypes!global.d.ts
中進行聲明定義types/
目錄下定義好其結構化類型聲明react中的組件從定義方式上來講,分爲類組件和函數式組件。html
類組件的聲明java
class App extends Component<IProps, IState> {
static defaultProps = {
// ...
}
readonly state = {
// ...
};
// 小技巧:若是state很複雜不想一個個都初始化,能夠結合類型斷言初始化state爲空對象或者只包含少數必須的值的對象: readonly state = {} as IState;
}
複製代碼
須要特別強調的是,若是用到了
state
,除了在聲明組件時經過泛型參數傳遞其state
結構,還須要在初始化state
時聲明爲readonly
react
這是由於咱們使用 class properties
語法對state
作初始化時,會覆蓋掉Component<P, S>
中對state
的readonly
標識。數組
// SFC: stateless function components
// v16.7起,因爲hooks的加入,函數式組件也可使用state,因此這個命名不許確。新的react聲明文件裏,也定義了React.FC類型^_^
const List: React.SFC<IProps> = props => null
複製代碼
是的
。只要在組件內部使用了props
和state
,就須要在聲明組件時指明其類型。state
,貌似即便沒有聲明state的類型,也能夠正常調用以及setState
。沒錯,實際狀況確實是這樣的,可是這樣子作實際上是讓組件丟失了對state
的訪問和類型檢查!// bad one
class App extends Component {
state = {
a: 1,
b: 2
}
componentDidMount() {
this.state.a // ok: 1
// 假如經過setState設置並不存在的c,TS沒法檢查到。
this.setState({
c: 3
});
this.setState(true); // ???
}
// ...
}
// React Component
class Component<P, S> {
constructor(props: Readonly<P>);
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
callback?: () => void
): void;
forceUpdate(callBack?: () => void): void;
render(): ReactNode;
readonly props: Readonly<{ children?: ReactNode }> & Readonly<P>;
state: Readonly<S>;
context: any;
refs: {
[key: string]: ReactInstance
};
}
// interface IState{
// a: number,
// b: number
// }
// good one
class App extends Component<{}, { a: number, b: number }> {
readonly state = {
a: 1,
b: 2
}
//readonly state = {} as IState,斷言所有爲一個值
componentDidMount() {
this.state.a // ok: 1
//正確的使用了 ts 泛型指示了 state 之後就會有正確的提示
// error: '{ c: number }' is not assignable to parameter of type '{ a: number, b: number }'
this.setState({
c: 3
});
}
// ...
}
複製代碼
什麼是 react 高階組件?裝飾器?react-router
props
進行修改(添加、刪除)等。這些會致使簽名一致性校驗失敗,TS
會給出錯誤提示。這帶來兩個問題:withRouter
:import { RouteComponentProps } from 'react-router-dom';
const App = withRouter(class extends Component<RouteComponentProps> {
// ...
});
// 如下調用是ok的
<App />
複製代碼
如上的例子,咱們在聲明組件時,註解了組件的props是路由的
RouteComponentProps
結構類型,可是咱們在調用App組件時,並不須要給其傳遞RouteComponentProps
裏說具備的location
、history
等值,這是由於withRouter
這個函數自身對齊作了正確的類型聲明。app
Partial
這個映射類型),或者將其聲明到額外的injected
組件實例屬性上。 咱們先看一個常見的組件聲明:import { RouteComponentProps } from 'react-router-dom';
// 方法一
@withRouter
class App extends Component<Partial<RouteComponentProps>> {
public componentDidMount() {
// 這裏就須要使用非空類型斷言了
this.props.history!.push('/');
}
// ...
});
// 方法二
@withRouter
class App extends Component<{}> {
get injected() {
return this.props as RouteComponentProps
}
public componentDidMount() {
this.injected.history.push('/');
}
// ...
複製代碼
interface IUserCardProps {
name: string;
avatar: string;
bio: string;
isAdmin?: boolean;
}
class UserCard extends Component<IUserCardProps> { /* ... */}
複製代碼
上面的組件要求了三個必傳屬性參數:name、avatar、bio,isAdmin是可選的。加入此時咱們想要聲明一個高階組件,用來給UserCard傳遞一個額外的布爾值屬性visible,咱們也須要在UserCard中使用這個值,那麼咱們就須要在其props的類型裏添加這個值:less
interface IUserCardProps {
name: string;
avatar: string;
bio: string;
visible: boolean;
isAdmin?: boolean;
}
@withVisible
class UserCard extends Component<IUserCardProps> {
render() {
// 由於咱們用到visible了,因此必須在IUserCardProps裏聲明出該屬性
return <div className={this.props.visible ? '' : 'none'}>...</div>
}
}
function withVisiable(WrappedComponent) {
return class extends Component {
render() {
return <WrappedComponent {..this.props} visiable={true} /> } } } 複製代碼
可能你此時想到了,把visible聲明爲可選。沒錯,這個確實就解決了調用組件時visible必傳的問題。這確實是個解決問題的辦法。可是就像上一個問題裏提到的,這種應對辦法應該是對付哪些沒有類型聲明或者聲明不正確的高階組件的。dom
因此這個就要求咱們能正確的聲明高階組件:函數
interface IVisible {
visible: boolean;
}
//排除 IVisible
function withVisible<Self>(WrappedComponent: React.ComponentType<Self & IVisible>): React.ComponentType<Omit<Self, 'visible'>> {
return class extends Component<Self> {
render() {
return <WrappedComponent {...this.props} visible={true} /> } } } 複製代碼
如上,咱們聲明withVisible這個高階組件時,利用泛型和類型推導,咱們對高階組件返回的新的組件以及接收的參數組件的props都作出類型聲明。