【2021-05-04】ts在ReactClass和ReactHooks的应用
对于现行的ES规范,已经具有很好的规范性与可读性,type script虽当下大行其道,其实我觉得意义不算很大,ts最重要的功能就是类型检查,包括 interface, type 等也是一种类型检查,但一不小心就会写成 any script。
鉴于将来的项目或者现行的项目可能会用到,这里结合 React Hooks 写个 tsx 版的 demo
安装
新项目,只需带--template typescript
参数即可:
1 2 3
| create-react-app <app name> --template typescript #or yarn create-react-app <app name> --template typescript
|
老项目,在原有JSX项目create-react-app
基础上增加typescript内容:
1 2 3 4 5
| npm install --save typescript @types/node @types/react @types/react-dom @types/jest # or yarn add typescript @types/node @types/react @types/react-dom @types/jest
|
创建*.d.ts
文件,专门用于各种依赖的声明
详细的用法可参考掘金答神这篇文章,我这里简单的说明一下:
外部npm install
一个库时:
interface
声明
1 2 3 4 5
| interface xxxProps { name: string; age?: number; method(f: string): string; }
|
初学者的编写利器 —— vs code
中的提示
可以利用好 vs code
中自带的提示,例如下面的提示,下面的例子会截图此类提示框:
最外层 index.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import React from 'react'; import ReactDOM from 'react-dom'; import App from './App';
declare global { interface Window { API: any, _store: any } }
ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') as HTMLElement );
|
组件
Function 组件
1
| const App: React.FC = () => null
|
vs code 里的提示:
Class 组件
1 2 3 4 5 6
| export class ClassTS extends React.Component { public render(): React.ReactNode { return null } }
|
props
Function 组件里的props
1 2 3 4 5 6 7 8 9 10 11 12 13
| export const TextField: React.FC<{ text: string }> = () => { return <div><input type="text"/></div> }
interface Props { text: string } export const TextField: React.FC<Props> = () => { return <div><input type="text"/></div> }
|
其中,接口也可随意扩展及定义子接口,如:
1 2 3 4 5 6 7 8 9 10 11 12 13
| interface Person { firstName: string lastName: string }
interface Props { text: string ok?: boolean i?: number fn?: (bob: string) => string person: Person }
|
Class 组件里的 props
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| export class ClassTS extends React.Component <{ text: string, age?: number }> { }
interface IProps { text: string age?: number }
interface IState { email: string name: string }
export class ClassTS extends React.Component <IProps> { state: IState = { name: '', email: '' } }
|
组件里的函数
React特有的类型,React.FormEvent,虚拟DOM把所有原生函数都撸了个遍:
1 2 3 4
| handleChange = ( e : React.FormEvent<HTMLInputElement> ) => { const { name, value } : any = e.target this.setState({ [name]: value }) }
|
函数组件的 hooks
useState
1 2 3 4 5 6 7 8
| const [count, setCount] = useState < string | null | { text: string } >({ text: 'hello' })
interface TextNode { text: string } const [count, setCount] = useState < number | TextNode >(5)
|
useRef
1 2 3 4
|
const inputRef = useRef<HTMLInputElement>(null)
|
另外,handleChange
1 2 3 4 5 6
| interface Props { handleChange: ( event: React.ChangeEvent<HTMLInputElement> ) => void }
|
useReducer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| interface Todos { text: string complete: boolean }
type State = Todos[] type Actions = { type: 'add', text: string } | { type:'remove', idx: number }
const TodoReducer = ( state: State, action: Actions ) => { switch (action.type) { case 'add': return [...state, { text: action.text, complete: false }] case 'remove': return state.filter((_, i) => action.idx !== i) default: return state; } }
const [todos, dispatch] = useReducer(TodoReducer, [])
|
hooks 的 render props
将 hooks 函数 setXXX
作为参数传参,这种props是react独有的,React.Dispatch<React.SetStateAction<number>>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| interface Props { children:( count: number, setCount: React.Dispatch<React.SetStateAction<number>> ) => JSX.Element | null }
export const Counter: React.FC<Props> = ({ children }) => { const [count, setCount] = useState(0) return <div> {children(count, setCount)} </div> }
|
另一种,原生的函数在虚拟DOM里的函数:
写的时候 vs code 里的提示: