Vite 搭建 React18 项目,分享一些使用技巧

54,825 阅读2分钟

初始化项目

npm init vite

package.json

{
  "name": "react18-demo",
  "private": true,
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite --host --port 3000",
    "build": "tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@ant-design/icons": "^4.8.0",
    "antd": "^4.24.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-redux": "^7.2.8",
    "react-router-dom": "^6.3.0",
    "redux": "^4.1.2",
    "redux-thunk": "^2.4.2"
  },
  "devDependencies": {
    "@types/node": "^18.11.9",
    "@types/react": "^18.0.24",
    "@types/react-dom": "^18.0.8",
    "@vitejs/plugin-react": "^2.2.0",
    "less": "^2.7.1",
    "sass": "^1.56.1",
    "typescript": "^4.6.4",
    "vite": "^3.2.3",
    "vite-plugin-style-import": "^1.4.1"
  }
}

配置 @ 别名

  • vite.config.ts
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import path from "path"

export default defineConfig({
  plugins: [ react() ],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src")
    }
  }
})
  • tsconfig.json
{
  "compilerOptions": {
    ...
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

类型定义

  • 在 src 目录下,新建 xxx.d.ts 文件 (vite 会自动读取.d.ts 文件识别类型定义)

可新建多个类型定义,如 type.d.tsapi.d.tsglobal.d.ts 等等 以 redux 使用到的类型为例子

type RootStateType = ReturnType<typeof import("@/store").getState>

interface Window {
  __REDUX_DEVTOOLS_EXTENSION__: function;
  __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: function
}

Redux 使用方式

新建目录及文件

  • src 目录下新建 store 目录,在 store 目录下新建 index.ts 文件

  • store 目录下 新建 user 目录,在 user 目录下新建 index.tsreducer.ts 两个文件

  • store 目录下 新建 num 目录,在 num 目录下新建 index.tsreducer.ts 两个文件

  • 两个目录下的 reducer.ts 文件内容如下:

import handle from "./index"

const reducer = (state = { ...handle.state }, action: { type: string, value: any }) => {
  let newState = JSON.parse(JSON.stringify(state))
  const actionList = Object.keys(handle.actions)
  if (actionList.some(item => item === action.type)) {
    handle.actions[action.type](newState, action.value)
  }
  return newState
}
export default reducer
  • usernum 两个目录下的 index.ts 文件内容如下:
// 存放方法, 写法使用箭头函数 xxx: () => {}
// 不可使用 xxx() {}
// 两个目录下的 actions 不用,自行调整即可,对应的是修改state中的值
const actions: any = {
  // 改变 state.age
  setAge: (newState: { age: number }, value: number) => {
    newState.age = value
  },
  // 改变 state.role
  setRole: (newState: { role: [] }, value: []) => {
    newState.role = value
  }
}
export default {
  // state 存放数据
  state: {
    name: "Lucky",
    role: [0, 1, 2, 3],
    sex: 0,
    age: 33
  },
  actions
}
  • store 目录下 index.ts 文件内容如下:
import { legacy_createStore, combineReducers, compose, applyMiddleware } from "redux"
import reduxThunk from "redux-thunk"
import user from "./user/reducer"
import num from "./num/reducer"

// 使用 combineReducers 合并多个模块的数据
const reducers = combineReducers({
  user,
  num
})

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose
const store = legacy_createStore(reducers, composeEnhancers(applyMiddleware(reduxThunk)))
export default store

使用 Redux

  • main.tsx 引入并注册 store
import React from "react"
import ReactDOM from "react-dom/client"
import { Provider } from "react-redux"
import store from "./store"
import { BrowserRouter } from "react-router-dom"
import App from "./App"

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <Provider store={ store }>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>
)

  • 页面中使用数据
import { useSelector, useDispatch } from "react-redux"

// 使用
const { num } = useSelector((state: RootStateType) => state.num)
const { role } = useSelector((state: RootStateType) => state.user)

// 调用 actions,改变 state 中的值
const dispatch = useDispatch()
const change = () => {
  dispatch({ type: "setAge", value: 100 })
}

Gitree 仓库地址