React➕TypeScript

引入React

import * as React from 'react'
import * as ReactDom from 'react-dom'
复制代码

这种引入方式被认为是最可靠的一种方式,推荐使用

另一种引入方式:

import React from 'react'
import ReactDom from 'react-dom'
复制代码

需要添加额外的配置:"allowSyntheticDefaultImports": true,

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}
复制代码

函数式组件声明方式

第一种:React.FunctionComponent

比较推荐的一种,简写形式React.FC


type AppProps = {
  message: string
}
 
const App: React.FC<AppProps> = ({ message, children }) => (
  <div>
    {message}
    {children}
  </div>
)
复制代码

使用React.FC声明函数组件和普通声明以及PropsWithChildren的区别:

  • React.FC显式的定义了返回类型,其他方式是隐式推导
  • React.FC对静态属性:displayName,propTypes,defaultProps提供了类型检查和自动补全
  • React.FC为children提供了隐式类型(ReactElement|null),但是目前提供的类型存在一些问题

比如以下用法React.FC会报类型错误:

const App: React.FC = props => props.children
const App: React.FC = () => [1, 2, 3]
const App: React.FC = () => 'hello'
复制代码

解决办法:

const App: React.FC<{}> = props => props.children as any
const App: React.FC<{}> = () => [1, 2, 3] as any
const App: React.FC<{}> = () => 'hello' as any
// 或者
const App: React.FC<{}> = props => (props.children as unknown) as JSX.Element
const App: React.FC<{}> = () => ([1, 2, 3] as unknown) as JSX.Element
const App: React.FC<{}> = () => ('hello' as unknown) as JSX.Element
复制代码

在通常情况下,使用React.FC的方式声明最简单有效,推荐使用;如果出现类型不兼容问题,建议以下两种方式

第二种:PropsWithChildren

这种方式可以省去频繁定义children的类型,自动设置children类型为ReactNode:

type AppProps = React.PropsWithChildren<{ message: string }>
const App = ({ message, children }: AppProps) => (
  <div>
    {message}
    {children}
  </div>
)
复制代码

第三种:直接声明

type AppProps = {
  message: string
  children?: React.ReactNode
}
 
const App = ({ message, children }: AppProps) => (
  <div>
    {message}
    {children}
  </div>
)
复制代码

Hooks

use State<T>

返回一个 state,以及更新 state 的函数

大部分情况下ts会自动推导state的类型:

// `val`会推导为boolean类型, toggle接收boolean类型参数
const [val, toggle] = React.useState(false)
// obj会自动推导为类型: {name: string}
const [obj] = React.useState({ name: 'sj' })
// arr会自动推导为类型: string[]
const [arr] = React.useState(['One', 'Two'])
复制代码

使用推导类型作为接口/类型:

export default function App() {
  // user会自动推导为类型: {name: string}
  const [user] = React.useState({ name: 'sj', age: 32 })
  const showUser = React.useCallback((obj: typeof user) => {
    return `My name is ${obj.name}, My age is ${obj.age}`
  }, [])
  return <div className="App">用户: {showUser(user)}</div>
}
复制代码

但是,一些状态初始值为空(null)时,需要显式的声明类型:

type User = {
  name: string
  age: number
}
const [user, setUser] = React.useState<User | null>(null)
复制代码

useRef<T>

useRef返回一个可变的ref对象,其.current属性被初始化为传入的参数。返回的ref对象在组件的整个生命周期内保持不变

当初始值为null时,有两种创建方式

const ref1 = React.useRef<HTMLInputElement>(null)
const ref2 = React.useRef<HTMLInputElement | null>(null)
复制代码

这两种的区别在于:

  • 第一种方式的ref1.current是只读的,并且可以传递给内置的ref属性,绑定DOM元素
  • 第二种方式的ref2.current是可变的(类似于声明类的成员变量)
const ref = React.useRef(0)
React.useEffect(() => {
  ref.current += 1
}, [])
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享