神族九帝's blog 神族九帝's blog
首页
  • 神卡套餐 (opens new window)
  • 神族九帝 (opens new window)
  • 网盘资源 (opens new window)
  • 今日热点 (opens new window)
  • 在线PS (opens new window)
  • IT工具 (opens new window)
  • FC游戏 (opens new window)
  • 在线壁纸 (opens new window)
  • 面试突击
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 工作笔记
  • 前端基础建设与架构 30 讲
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • 思维导图
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • React
  • 更多
  • 未来要做的事
  • Stirling-PDF
  • ComfyUI
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 收藏夹
  • 更多
GitHub (opens new window)

神族九帝,永不言弃

首页
  • 神卡套餐 (opens new window)
  • 神族九帝 (opens new window)
  • 网盘资源 (opens new window)
  • 今日热点 (opens new window)
  • 在线PS (opens new window)
  • IT工具 (opens new window)
  • FC游戏 (opens new window)
  • 在线壁纸 (opens new window)
  • 面试突击
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 工作笔记
  • 前端基础建设与架构 30 讲
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • 思维导图
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • React
  • 更多
  • 未来要做的事
  • Stirling-PDF
  • ComfyUI
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 收藏夹
  • 更多
GitHub (opens new window)
  • 工作笔记

  • 前端基础建设与架构 30 讲

  • vue2源码学习

  • 剖析vuejs内部运行机制

  • TypeScript 入门实战笔记

  • vue3源码学习

  • 2周刷完100道前端优质面试真题

  • 思维导图

  • npm发包

  • 重学node

  • 前端性能优化方法与实战

  • webpack原理与实战

  • webGl

  • 前端优化

  • Web3

  • React

    • react基础教程
      • 环境搭建
      • JSX
        • 在 jsx 中可以通过 {} 来使用 js 表达式,但是不能使用 if else 语句,可以使用三元运算符
        • jsx 中可以使用map实现列表渲染
        • jsx 中实现条件渲染
        • jsx 实现复杂条件渲染
      • 事件绑定
        • 使用时间对象参数
        • 同时传递事件对象和自定义参数
      • useState
        • 状态不可变
        • 修改对象状态
      • 组件的样式处理
        • 内联样式
        • class样式
      • 组件通讯
        • 父子
        • 子父
        • 兄弟
      • useEffect
        • 基础使用
        • useEffect 依赖项参数说明
        • 清除副作用
      • 自定义hook
      • React Hooks 使用规则
      • redux 快速上手
      • Redux 基本使用
        • redux-toolkit
        • react-redux
        • 配置基础环境
        • store 目录设计
        • 使用redux-toolkit创建counterStore
        • 为react注入store
        • react组件使用store中的数据
        • react组件修改store中的数据
      • 异步状态操作
      • react-router
        • 路由导航
        • 路由传参
        • 嵌套路由配置
        • 默认二级路由
        • 404 路由配置
        • 两种路由模式
        • 路由懒加载
        • 路径别名
      • 打包体积优化
      • 性能相关优化Api
        • useReducer
        • useMemo
        • memo 和 props 的比较机制
        • useCallback
        • React.forwardRef
        • useImperativeHandle
        • Class
        • zustand
      • vite
      • useState与TS
      • 资源
    • create-react-app
  • 更多

  • 笔记
  • React
wu529778790
2020-11-08

react基础教程

多一句没有,少一句不行,用更短时间,教会更实用的技术!

https://zh-hans.react.dev/learn/start-a-new-react-project (opens new window)

# 环境搭建

create-react-app

npx create-react-app my-app
cd my-app
npm start

# JSX

JSX 是 JavaScript 的语法扩展。React 使用 JSX 来替代常规的 JavaScript。浏览器不能直接解析JSX,需要使用babel进行编译

https://babeljs.io/repl/#?browsers=defaults%2C not ie 11%2C not ie_mob 11&build=&builtIns=false&corejs=3.21&spec=false&loose=false&code_lz=DwEwlgbgfAUAkAFwBZgM4AI3vBGwD0OUQA&debug=false&forceAllTransforms=false&modules=false&shippedProposals=false&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Creact%2Cstage-2&prettier=false&targets=&version=7.26.2&externalPlugins=&assumptions={} (opens new window)

20241108144358

# 在 jsx 中可以通过 {} 来使用 js 表达式,但是不能使用 if else 语句,可以使用三元运算符

if语句、switch语句、变量声明属于语句,不是表达式,不能出现在{}中

# jsx 中可以使用map实现列表渲染

const list = [1, 2, 3, 4, 5];
const listItems = list.map((item) => <li>{item}</li>);

# jsx 中实现条件渲染

在React中,可以通过逻辑与运算符&&、三元表达式(?:)实现基础的条件渲染

const isLogin = true;
const element = isLogin ? <div>登录成功</div> : <div>登录失败</div>;

# jsx 实现复杂条件渲染

列表中需要根据文章状态适配三种情况,单图,三图,和无图三种模式

自定义函数 + if判断语句

function getArticleType(article) {
  if (article.images.length === 1) {
    return <div>单图</div>;
  } else if (article.images.length === 3) {
    return <div>三图</div>;
  } else {
    return <div>无图</div>;
  }
}

# 事件绑定

on + 事件名称 = { 事件处理程序 },整体上遵循驼峰命名法

# 使用时间对象参数

在事件回调函数中设置形参e

function App() {
  function handleClick(e) {
    console.log(e);
  }
  return (
    <div>
      <button onClick={handleClick}>点我</button>
    </div>
  );
}

传递自定义参数

事件绑定的位置改造成箭头函数的写法,在执行clickHandler实际处理业务函数的时候传递实参

function App() {
  function handleClick(name) {
    console.log(name);
  }
  return (
    <div>
      <button onClick={() => handleClick("wu")}>点我</button>
    </div>
  );
}

不能直接写函数调用,这里事件绑定需要一个函数引用,而不是函数调用,所以需要使用箭头函数

# 同时传递事件对象和自定义参数

function App() {
  function handleClick(e, name) {
    console.log(e, name);
  }
  return (
    <div>
      <button onClick={(e) => handleClick(e, "wu")}>点我</button>
    </div>
  );
}

# useState

useState 是一个 React Hook(函数),它允许我们向组件添加一个状态变量, 从而控制影响组件的渲染结果.

本质:和普通JS变量不同的是,状态变量一旦发生变化组件的视图UI也会跟着变化(数据驱动视图)

const [count, setCount] = useState(0); // count 是状态变量,setCount 是修改状态变量的方法
  1. useState是一个函数,返回值是一个数组
  2. 数组中的第一个参数是状态变量,第二个参数是set函数用来修改状态变量
  3. useState的参数是状态变量的初始值

# 状态不可变

在React中,状态被认为是只读的,我们应该始终替换它而不是修改它,直接修改状态不能引发视图更新

const [count, setCount] = useState(0);
const handleClick = () => {
    count = count + 1; // 错误写法
    setCount(count + 1); // 正确写法
};

# 修改对象状态

const [person, setPerson] = useState({ name: "wu", age: 18 });
const handleClick = () => {
    person.age = "19"; // 错误写法
    setPerson({ ...person, age: 19 }); // 正确写法
};

# 组件的样式处理

React组件基础的样式控制有俩种方式

# 内联样式

<div style={{ color: "red" }}>hello world</div>

# class样式

<div className="red">hello world</div>

# 组件通讯

# 父子

props 可传递任意的数据

数字、字符串、布尔值、数组、对象、函数、组件(jsx)

<Child name="wu" age={18} />

props 是只读的,不能直接修改

props.name = "wu2"; // 错误写法

特殊的父传子

当我们把内容嵌套在子组件中时,子组件的props中会自动接收到父组件传递过来的内容,放到props.children中

<Child>
    <div>hello world</div>
</Child>

console.log(props.children); // 打印 hello world

# 子父

子组件通过调用父组件传递过来的方法,来修改父组件中的状态变量

function Parent() {
    const [count, setCount] = useState(0);
  return <Child setCount={setCount} count={count} />;
}

function Child(props) {
    return <button onClick={() => props.setCount(props.count + 1)}>点我</button>
}

# 兄弟

兄弟组件之间不能直接通讯,需要通过共同的父组件来实现通讯

20241111173353

使用状态提升实现兄弟组件通讯

  1. A组件先通过子传父的方式把数据传给父组件App
  2. App拿到数据后通过父传子的方式再传递给B组件

使用context机制实现跨层级组件通讯

20241111173500

  1. 使用createContext方法创建一个上下文对象Ctx
  2. 在顶层组件(App)中通过 Ctx.Provider 组件提供数据
  3. 在后代组件中通过 Ctx.Consumer 组件消费数据

# useEffect

useEffect 是一个 React Hook(函数),用于在React组件中创建不是由事件引起而是由渲染本身引起的操作(副作用),比如发送AJAX请求,更改DOM等等。

20241111173702

上面的组件中没有发生任何的用户事件,组件渲染完毕之后就需要和服务器要数据,整个过程属于“只由渲染引起的操作”,所以需要使用useEffect来实现

# 基础使用

在组件渲染完毕之后,立刻从服务端获取频道列表数据并显示到页面中

useEffect(() => {
    axios.get("https://api.shenzjd.com").then((res) => {
        console.log(res);
    });
}, []);

参数1是一个函数,可以把它叫做副作用函数,在函数内部可以放置要执行的操作 参数2是一个数组(可选参),在数组里放置依赖项,不同依赖项会影响第一个参数函数的执行,当是一个空数组的时候,副作用函数只会在组件渲染完毕之后执行一次

# useEffect 依赖项参数说明

依赖项 副作用函数执行情况
没有依赖项 组件初始渲染 + 组件更新时执行
空数组 只在初始渲染时执行一次
添加特定依赖项 组件初始渲染 + 特性依赖项变化时执行

# 清除副作用

在useEffect中编写的由渲染本身引起的对接组件外部的操作,社区也经常把它叫做副作用操作,比如在useEffect中开启了一个定时器,我们想在组件卸载时把这个定时器再清理掉,这个过程就是清理副作用

useEffect(() => {
    const timer = setInterval(() => {
        console.log("hello world");
    }, 1000);
    return () => {
        clearInterval(timer);
    };
}, []);

说明:清除副作用的函数最常见的执行时机是在组件卸载时自动执行

# 自定义hook

自定义Hook是以 use 打头的函数,通过自定义Hook函数可以用来实现逻辑的封装和复用

20241111174416

# React Hooks 使用规则

  1. 只能在组件中或者其他自定义Hook函数中调用
  2. 只能在组件的顶层调用,不能嵌套在 if、for、其他函数中

20241111174804

# redux 快速上手

Redux 是React最常用的集中状态管理工具,类似于Vue中的Pinia(Vuex),可以独立于框架运行作用:通过集中管理的方式管理应用的状态

20241111174859

为了职责清晰,数据流向明确,Redux把整个数据修改的流程分成了三个核心概念,分别是:state、action和reducer

  1. state - 一个对象 存放着我们管理的数据状态
  2. action - 一个对象 用来描述你想怎么改数据
  3. reducer - 一个函数 更具action的描述生成一个新的state

20241111174941

# Redux 基本使用

https://cn.redux.js.org/ (opens new window)

https://redux-toolkit.js.org/ (opens new window)

# redux-toolkit

Redux Toolkit(RTK)- 官方推荐编写Redux逻辑的方式,是一套工具的集合集,简化书写方式

pnpm install @reduxjs/toolkit
  • 简化store的配置方式
  • 内置immer支持可变式状态修改
  • 内置thunk更好的异步创建

# react-redux

react-redux - 用来 链接 Redux 和 React组件 的中间件

pnpm install react-redux

20241112103216

# 配置基础环境

  1. 使用 CRA 生成项目
npx create-react-app my-app
// 或者
pnpm dlx create-react-app my-app
  1. 安装@reduxjs/toolkit和react-redux
pnpm install react-redux @reduxjs/toolkit
  1. 启动项目
pnpm run start

# store 目录设计

20241112103437

  1. 通常集中状态管理的部分都会单独创建一个单独的 store 目录
  2. 应用通常会有很多个子store模块,所以创建一个 modules 目录,在内部编写业务分类的子store
  3. store中的入口文件 index.js 的作用是组合modules中所有的子模块,并导出store

20241112103614

# 使用redux-toolkit创建counterStore

// counterStore.js
import { createSlice } from '@reduxjs/toolkit'

const counterStore = createSlice({
  name: 'counter',
  // 初始状态数据
  initialState: {
    count: 0
  },
  // 修改数据的方法 同步方法 支持直接修改
  reducers: {
    increment(state) {
      state.count++
    },
    decrement(state) {
      state.count--
    }
  }
})

// 解构出来 actionCreater函数
const { increment, decrement } = counterStore.actions

// 获取reducer
const counterReducer = counterStore.reducer

// 导出
export { increment, decrement }
export default counterReducer
// store/index.js
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './modules/counterStore'

const store = configureStore({
  reducer: { 
    counter: counterReducer
  }
})

# 为react注入store

react-redux 负责把Redux和React 链接 起来,内置 Provider组件 通过 store 参数把创建好的store实例注入到应用中,链接正式建立

import { Provider } from 'react-redux'
import { store } from './store'

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
  <Provider store={store}>
    <App />
  </Provider>
)

# react组件使用store中的数据

在React组件中使用store中的数据,需要用到一个 钩子函数 - useSelector,它的作用是把store中的数据映射到组件中

import { useSelector } from 'react-redux'

const count = useSelector(state => state.counter)

20241112105330

# react组件修改store中的数据

React组件中修改store中的数据需要借助另外一个hook函数 - useDispatch,它的作用是生成提交action对象的dispatch函数

import { useDispatch, useSelector } from 'react-redux'
import { increment, decrement } from './store/modules/counterStore'

function App() {
  const count = useSelector(state => state.counter)
  const dispatch = useDispatch()
  return (
    <div className='App'>
      <button onClick={() => dispatch(increment())}>+</button>
      <span>{count.count}</span>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  )
}

# 异步状态操作

20241112105909

  1. 创建store的写法保持不变,配置好同步修改状态的方法
  2. 单独封装一个函数,在函数内部return一个新函数,在新函数中 2.1 封装异步请求获取数据 2.2 调用同步actionCreater传入异步数据生成一个action对象,并使用dispatch提交
  3. 组件中dispatch的写法保持不变
const channelStore = createSlice({
  name: 'channel',
  initialState: {
    channelList: []
  },
  reducers: {
    getChannelList(state, action) {
      state.channelList = action.payload
    }
  }
})
const { setChannelList } = channelStore.actions

const fetchChannelList = () => {
  return async dispatch => {
    const res = await axios.get('https://api.shenzjd.com')
    dispatch(setChannelList(res.data.data.channels))
  }
}

export { fetchChannelList }
import { useDispatch } from 'react-redux'
import { fetchChannelList } from './store/modules/channelStore'

function App() {
  const dispatch = useDispatch()
  useEffect(() => {
    dispatch(fetchChannelList())
  }, [dispatch])
}

# react-router

pnpm install react-router-dom

# 路由导航

路由系统中的多个路由之间需要进行路由跳转,并且在跳转的同时有可能需要传递参数进行通信

声明式导航

<Link to="/">首页</Link>

编程式导航

import { useNavigate } from 'react-router-dom'

const Login = () => {
    const navigate = useNavigate()
    return (
      <div onClick={() => navigate('/')}>登录</div>
    )
}

# 路由传参

searchParams

navigate('/login?name=wu&age=18')
import { useSearchParams } from 'react-router-dom'
const [searchParams, setSearchParams] = useSearchParams()
console.log(searchParams.get('name'))

params

navigate('/login/wu/18')
import { useParams } from 'react-router-dom'
const params = useParams()
console.log(params.name)

# 嵌套路由配置

在一级路由中又内嵌了其他路由,这种关系就叫做嵌套路由,嵌套至一级路由内的路由又称作二级路由

20241112163222

  1. 使用 children 属性配置路由嵌套关系
  2. 使用 <Outlet/> 组件配置二级路由渲染位置
const routes = [
    {
        path: '/',
        element: <Layout />,
        children: [
          { path: 'login', element: <Login /> },
          { path: 'register', element: <Register /> }
        ]
    }
]
const Layout = () => {
    return (
        <div>
            <h1>Layout</h1>
            <div>
                <Link to="/login">登录</Link>
                <Link to="/register">注册</Link>
            </div>
            <Outlet />
        </div>
    )
}

# 默认二级路由

当访问的是一级路由时,默认的二级路由组件可以得到渲染,只需要在二级路由的位置去掉path,设置index属性为true

{ 
  path: '/', 
  element: <Layout />, 
  children: [
    { index: true, element: <Home /> },
    { path: 'login', element: <Login /> },
    { path: 'register', element: <Register /> }
  ]
}

# 404 路由配置

当访问的路由在配置中不存在时,会自动匹配到404路由,并渲染404组件

{ 
  path: '*', 
  element: <NotFound /> 
}

# 两种路由模式

history模式和hash模式, ReactRouter分别由createBrowerRouter和createHashRouter 函数负责创建

模式 url实现 底层原理 是否需要后端支持
history url/login history对象 + pushState事件 需要后端支持
hash url#login 监听 hashchange 事件 不需要后端支持

# 路由懒加载

路由懒加载是指路由的JS资源只有在被访问时才会动态获取,目的是为了优化项目首次打开的时间

import { lazy } from 'react'

const Login = lazy(() => import('./views/Login'))

# 路径别名

pnpm install @craco/craco

craco.config.js

const path = require('path')

module.exports = {
    // plugins: [
    //   { plugin: require('@craco/craco') }
    // ],
    webpack: {
      alias: {
        '@': path.resolve(__dirname, './src')
      }
    }
}

修改package.json

"scripts": {
  "start": "craco start",
  "build": "craco build"
}

联想路径配置

VsCode的联想配置,需要我们在项目目录下添加 jsconfig.json 文件,加入配置之后VsCode会自动读取配置帮助我们自动联想提示

根目录下新增配置文件 - jsconfig.json

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": { 
      "@/*": ["src/*"] 
    }
  }
}

# 打包体积优化

pnpm install source-map-explorer

# 性能相关优化Api

# useReducer

useReducer 和 useState 的区别

  • useState 适合管理简单状态数据
  • useReducer 适合管理复杂状态数据

20241112165321

作用:和useState的作用类似,用来管理相对复杂的状态数据

  1. 定义一个reducer函数(根据不同的action返回不同的新状态)
  2. 在组件中调用useReducer,并传入reducer函数和状态的初始值
  3. 事件发生时,通过dispatch函数分派一个action对象(通知reducer要返回哪个新状态并渲染UI)
function reducer(state, action) {
    switch (action.type) {
        case 'INC': return state + 1
        case 'DEC': return state - 1
        default: return state
    }
}
const [state, dispatch] = useReducer(reducer, 0)
dispatch({ type: 'INC' })

useReducer 分派action时传参

20241112165252

# useMemo

在组件每次重新渲染的时候缓存计算的结果

const result = useMemo(() => {
    // 根据count1返回计算的结果
}, [count1])

使用useMemo做缓存之后可以保证只有count1依赖项发生变化时才会重新计算

作用:允许组件在Props没有改变的情况下跳过渲染

React组件默认的渲染机制:只要父组件重新渲染子组件就会重新渲染

20241112170222

如果Son组件本身并不需要做渲染更新,是不是存在浪费?

const MemoComponent = memo(function SomeComponent(props) {
    return <div>SomeComponent</div>
})

经过memo函数包裹生成的缓存组件只有在props发生变化的时候才会重新渲染

# memo 和 props 的比较机制

在使用memo缓存组件之后,React会对每一个 prop 使用 Object.is 比较新值和老值,返回true,表示没有变化

prop是简单类型

Object.is(3, 3) => true 没有变化

prop是引用类型(对象 / 数组)

Object([], []) => false 有变化,React只关心引用是否变化

# useCallback

在组件多次重新渲染的时候缓存函数

const Input = memo(function Input({onChange}) {
    console.log('Input组件重新渲染')
    return <input type="text" onChange={e => onChange(e.target.value)} />
})

function App() {
    // 传递给子组件的函数
    const changeHandler = useCallback(value => {
        console.log(value)
    }, [])
    // 触发父组件重新渲染的函数
    const [value, setValue] = useState(0)
    return (
        <div className='App'>
            <Input onChange={changeHandler} />
            <button onClick={() => setValue(value + 1)}>+</button>
        </div>
    )
}

使用useCallback包裹函数之后,函数可以保证在App重新渲染的时候保持引用稳定

# React.forwardRef

使用ref暴露DOM节点给父组件

20241112170925

const Input = forwardRef(function Input(props, ref) {
    return <input {...props} ref={ref} />
})

function App() {
    const inputRef = useRef(null)
    return <Input ref={inputRef} />
}

# useImperativeHandle

通过ref暴露子组件中的方法

20241112171037

const Input = forwardRef((props, ref) => {
    const inputRef = useRef(null)
    const focus = () => {
        inputRef.current.focus()
    }
    useImperativeHandle(ref, () => ({
        focus
    }))
    return <input {...props} ref={inputRef} />
})

# Class

类组件的写法

类组件就是通过JS中的类来组织组件的代码

  1. 通过类属性state定义状态数据
  2. 通过setState方法来修改状态数据
  3. 通过render来写UI模版(JSX语法一致)
class Counter extends Component {
    state = {
        count: 0
    }
    clickHandler = () => {
        this.setState({ count: this.state.count + 1 })
    }
    render() {
        return <div onClick={this.clickHandler}>{this.state.count}</div>
    }
}

# 类组件的生命周期

组件从创建到销毁的各个阶段自动执行的函数就是生命周期函数

20241112171715

  1. componentDidMount:组件挂载完毕自动执行 - 异步数据获取
  2. componentWillUnmount: 组件卸载时自动执行 - 清理副作用

# zustand

极简的状态管理工具

20241112171825

# 异步支持

对于异步的支持不需要特殊的操作,直接在函数中编写异步逻辑,最后只需要调用set方法传入新状态即可

const useStore = create(set => {
  return {
    channelList: [],
    fetchChannelList: async () => {
      const res = await axios.get('https://api.shenzjd.com')
      set({ channelList: res.data.data.channels })
    }
  }
})

# 切片模式

当单个store比较大的时候,可以采用 切片模式 进行模块拆分组合,类似于模块化

20241112172027

# vite

pnpm create vite

# 使用react模板
pnpm create vite my-app -- --template react-ts

# useState与TS

useState本身是一个泛型函数,可以传入具体的自定义类型

type User = {
  name: string
  age: number
}
const [user, setUser] = useState<User>({ name: 'wu', age: 18 })
  1. 限制useState函数参数的初始值必须满足类型为: User | ()=> User
  2. 限制setUser函数的参数必须满足类型为:User | ()=> User | undefined
  3. user状态数据具备User类型相关的类型提示

useState-初始值为null

当我们不知道状态的初始值是什么,将useState的初始值为null是一个常见的做法,可以通过具体类型联合null来做显式注解

type User = {
  name: string
  age: number
}
const [user, setUser] = useState<User | null>(null)
  1. 限制useState函数参数的初始值可以是 User | null
  2. 限制setUser函数的参数类型可以是 User | null

props与TypeScript

为组件prop添加类型,本质是给函数的参数做类型注解,可以使用type对象类型或者interface接口来做注解

type Props = {
  name: string
}

function Button(props: Props) {
  return <button>{props.name}</button>
}

props与TypeScript - 为children添加类型

children是一个比较特殊的prop, 支持多种不同类型数据的传入,需要通过一个内置的ReactNode类型来做注解

type Props = {
  children: ReactNode
}

function Button(props: Props) {
  return <button>{props.children}</button>
}

注解之后,children可以是多种类型,包括:React.ReactElement 、string、number、React.ReactFragment 、React.ReactPortal 、boolean、 null 、undefined

# 资源

我用夸克网盘分享了「黑马程序员-react教程.pdf」,点击链接即可保存。打开「夸克APP」在线查看,支持多种文档格式转换。 链接:https://pan.quark.cn/s/d29ef5ff01f9 (opens new window) 提取码:X7bX

编辑 (opens new window)
上次更新: 2025/03/17, 12:21:00
我的第一个NFT
create-react-app

← 我的第一个NFT create-react-app→

最近更新
01
Code Review
10-14
02
ComfyUI
10-11
03
vscode插件开发
08-24
更多文章>
Power by vuepress | Copyright © 2015-2025 神族九帝
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×