4.3-React+TypeScript
Create by fall on 2022-04-05 Recently revised in 2022-04-05
安装
- 使用
create-react-app
添加模板
npx create-react-app my-app --template typescript
使用
React.FC
是 TypeScript 中的一个泛型,FC 是 Function Component 的缩写,也可以写为 React.FunctionComponent
// 泛型中包含了 PropsWithChildren 的泛型,所以不需要定义 children,如果要添加其他属性,需要添加类型注释,比如这里的 message
const MyComponent:React.FC<{message:string}> = ({message})=>{
return (
<div>{message}</div>
)
}
Hooks
useState
import {useState} from 'react'
const [val,setVal] = useState(22)
// 没有初始值,或者是 null
type AppProps = {message:string}
const App = ()=>{
const [data] = useState<AppProps |null>(null)
return <div>{data?.message}</div>
}
useEffect
import {useEffect} from 'react'
function DealyedEffect(props:{timerMs:number}){
const {timerMs} = props
useEffect(()=>{
const timer = setTimeout(()=>{
console.log('yep')
},timerMs)
return ()=>clearTimeout(timer)
},[timerMs])
return null
}
useEffect(()=>{
(async ()=>{
const {data} = await ajax(params)
})()
},[params])
useEffect(()=>{
ajax(params).then(res=>{
// todo
})
})
useRef
function TextInputWithFocusButton(){
const inputEl = React.useRef<HTMLInputElement>(null)
const onButtonClick = ()=>{
if(inputEl && inputEl.current){
input.current.focus()
}
inputEl.current?.focus()
}
return (
<div>
<input ref={inputEl} type='text' />
<button onClick={onButtonClick}>Focus on Input</button>
</div>
)
}
useReducer
一个钩子,牛逼的钩子,先传入方法,后传入初始参数,return的值,就是函数的值
const initialState = { count: 0 }
type ACTIONTYPE =
| { type: 'increment', payload: number }
| { type: 'decrement', payload: string }
| { type: 'inital' }
function reducer(state: typeof initialState, action: ACTIONTYPE) {
switch (action.type) {
case 'increment':
return { count: state.count + action.payload }
case 'decrement':
return { count: state.count - Number(action.payload) }
case 'inital':
return { count: initialState.count }
default:
throw new Error()
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<div>
剩余卡:{state.count}
<button onClick={() => dispatch({ type: 'decrement', payload: '2' })}>抛卡!</button>
<button onClick={() => dispatch({ type: 'increment', payload: 3 })}>加卡!</button>
<button onClick={() => dispatch({ type: 'inital' })}>归零</button>
</div>
)
}
useContext
useContext 和 useReducer 结合使用,用来管理全局数据流
interface AppContextInterface {
state:typeof initialState
dispatch:React.Dispatch<ACTIONTYPE>
}
// 创建 context
const AppCtx = React.createContext<AppContextInterface>({
state:initialState,
dispatch:(action)=>action
})
const App = ():React.ReactNode=>{
const [state,dispathc]=useReducer(reducer,initialState)
return (
<AppCtx.provider value={{state,disatch}}>
<Counter />
</AppCtx.provider>
)
}
// 使用 context
function Consumer(){
const {state,dispatch} = React.useContext(AppCtx)
return (
<div>
Count:{state.count}
<button onClick={()=>dispatch({type:'decrement',payload:'5'})}>-</button>
<button onClick={()=>dispatch({type:'increment',payload:5})}>-</button>
</div>
)
}
自定义 Hooks
export function useLoading(){
const [isLoading,setState] = React.useState(false)
const load = (onePromise:Promise<any>)=>{
setState(true)
return onePromise.finally(()=setState(false))
}
return [isLoading,load] as const
// return [isLoading,load] as [boolean,(onePromise:Promise<any>)=>Promise<any>]
}
// 元组
function tuplify<T extends any[]>(...elements:T){
return elements
}
function useArray(){
const numberValue = useRef(3).current
const functionValue = useRef(()=>{}).current
return [numberValue,functionValue] as const
}
function useTuple(){
const numberValue = useRef(3).current
const functionValue = useRef(()=>{}).current
return tuplify(numberValue,functionValue)
}
const initVal = {
name:'刘华',
count:0
}
type DealType={
type:'add'
value:number
}|{
type:'reduce'
value:number
}
function handsome(state:typeof initVal,deal:DealType){
switch(deal.type){
case 'add':
return {name:'刘华',count:deal.value+state.count}
case 'reduce':
return {name:'刘华',count:state.count-deal.value}
default:
throw new Error('没有对应的 useReduce操作')
}
}
const App:React.FC = function(){
const [state,dispatch] = useReducer(handsome,{name:'',count:1})
return (
<div>
当前的人名:{state.name}
<div></div>
当前的钱:{state.count}
<button onClick={()=>dispatch({type:'add',value:20})}>加钱</button>
<button onClick={()=>dispatch({type:'reduce',value:177})}>扣钱</button>
</div>
)
}
Hello World
// src/components/Hello.tsx
import * as React from 'react'
export interface Props{
name:string
enthusiasmLevel?:number
}
function Hello({name,enthusiasmLevel=1}:Props){
if(enthusiasmLevel <=0){
throw new Error('you should have a talk with your friends')
}
return (
<div className="hello">
<div className="greeting">
Hello{name+getExclamationMarks(enthusiasmLevel)}
</div>
</div>
)
}
function getExclamationMarks(numChars:number){
return Array(numChars + 1).join('!')
}