react+vite+ts+antd 搭建项目基础框架

Jiafeng

分类: React 856 0

前言

  • 距离上一个vue重构react项目已经有几个月了,最近在用vite写一些vue3的相关东西,看到vite支持react-ts模板,正好来体验下。

一、创建项目

pnpm create vite vite-react-test(自定义项目名称) --template react-ts
cd vite-react-test
pnpm install
pnpm run dev

目录结构如下:

  • 通过alias配置@别名,替代../../方式访问
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  server: {
    open: true
  },
  resolve: { // 设置项目文件导入路径
    alias: [
      { find: '@', replacement: path.resolve(__dirname, './src') }
    ]
  }
})
// tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "baseUrl": ".", // 新增
    "paths": { // 新增
      "@/*":["src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx"],
  "references": [{ "path": "./tsconfig.node.json" }]
}
  • 这里需要安装两个依赖
pnpm install @types/node path

二、引入react-router-dom

pnpm install react-router-dom
  • 在src目录下创建route文件夹,配置路由文件
// src/route/route-config.ts
import { lazy } from 'react'

const Login = lazy(() => import('@/pages/login'))
const Home = lazy(() => import('@/pages/home'))
const NotFound = lazy(() => import('@/pages/404'))
const RouteDemo = lazy(() => import('@/pages/demo/route-demo'))
const ReduxDemo = lazy(() => import('@/pages/demo/redux-demo'))
const ContextDemo = lazy(() => import('@/pages/demo/context-demo/view'))

export default [
    {
        path: '/',
        meta: {
            title: '首页',
            isLogin: true
        },
        component: Home
    },
    {
        path: '/login',
        meta: {
            title: '登录'
        },
        component: Login
    },
    {
        path: '/demo',
        component: lazy(() => import('@/pages/demo')),
        children: [
            {
                path: '',
                redirect: '/demo/route-demo',
            },
            {
                path: '/demo/route-demo/*',
                meta: {
                    title: 'react-route',
                    isLogin: true
                },
                component: RouteDemo,
            },
            {
                path: '/demo/redux-demo',
                meta: {
                    title: 'react-redux',
                    isLogin: true
                },
                component: ReduxDemo
            },
            {
                path: '/demo/context-demo',
                meta: {
                    title: 'react-context',
                    isLogin: true
                },
                component: ContextDemo
            }
        ]
    },
    {
        path: '*',
        meta: {
            title: '404'
        },
        component: NotFound
    }
]
// src/route/index.tsx
import { Suspense } from 'react' // Suspense的作用是「划分页面中需要并发渲染的部分」
import { Navigate, useRoutes } from 'react-router-dom'
import routes from './route-config'
// 拦截
const RouterBeforeEach = (props: { route: any, children: any }) => {
    if (props?.route?.meta?.title) {
        document.title = props.route.meta.title;
    }
    // const isLogin: boolean = !!Cookies.get('userInfo')
    const isLogin: boolean = true
    if (props?.route?.meta?.isLogin) {
        if (!isLogin) {
            return <Navigate to={'/login'} replace />
        }
    }
    // const location = useLocation()
    const location = { pathname: '' }
    const routerKey = location.pathname
    if (isLogin && ['/login'].includes(routerKey)) {
        return <Navigate to={'/'} replace />
    }
    return (
        <Suspense>
            {props.children}
        </Suspense>
    )
}
// 渲染路由
const renderRoutes = (routes: any) => {
    return routes.map((item: any) => {
        const route: any = { meta: item.meta, path: item.path }
        if (item.component) {
            // element 要接收react.element类型 item.component 是对象 所以要转一下
            // 看着里看着里 
            route.element = <RouterBeforeEach route={item}><item.component /></RouterBeforeEach>
        }
        if (item.children) {
            route.children = renderRoutes(item.children)
        }
        if (item.redirect) {
            route.element = <Navigate to={item.redirect} />
        }
        return route
    })
}

export default function Router() {
    // console.log(renderRoutes(routes));
    // useRoutes API 把路由数组整合为 <Router> <Route path="xx" element="xxx"></Route>等 </Router>的路由组件  直接用于BrowserRouter中
    return useRoutes(renderRoutes(routes))
}
  • 在src/App.tsx文件中引入写好的路由
// src/App.tsx
import Router from '@/route/index'
import { BrowserRouter } from 'react-router-dom'
function App() {

  return (
    <div className="App">
      <BrowserRouter>
        <Router></Router>
      </BrowserRouter>
    </div>
  )
}

export default App

三、引入react-redux@reduxjs/toolkit

pnpm install react-redux @reduxjs/toolkit
  • 在src目录下创建store文件夹,配置redux文件
// src/store/index.ts
import  {configureStore} from '@reduxjs/toolkit'
import counterSlice from './redux-toolkit/counterSlice'

export default configureStore({
    reducer: {
        counter: counterSlice
    }
})
// src/store/redux-toolkit/counterSlice.ts
import { createSlice } from '@reduxjs/toolkit'

interface typeState {
    count: number,
    title: string
}

const initialState: typeState = {
    count: 1,
    title: 'redux-toolkit'
}

export const counterSlice = createSlice({
    name: 'counter',
    initialState,
    reducers: {
        increment(state, { payload }) {
            state.count = state.count + payload.step;
        },
        decrement(state, { payload }) {
            console.log(payload)
            state.count -= payload.step
        }
    }
})

export const { increment, decrement } = counterSlice.actions

export const asyncdecrement = (payload: any) => (dispatch: (arg0: { payload: any; type: string; }) => void) => {
    setTimeout(() => {
        dispatch(decrement(payload))
    }, 2000)
}

export default counterSlice.reducer
  • 在src/main.tsx文件中引入store
// src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { Provider } from 'react-redux'
import store from './store/index'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
)
  • 使用方式如下:
// src\pages\demo\redux-demo\index.tsx
import { useSelector, useDispatch } from 'react-redux'
import { increment, asyncdecrement } from '@/store/redux-toolkit/counterSlice'

const ReduxDemo = () => {
    const { count } = useSelector((state: any) => state.counter)
    const dispatch: any = useDispatch()
    return (
        <>
            redux-demo
            <p>redux-toolkit demo 同步<button onClick={() => { dispatch(increment({ step: 2 })) }}>{count}</button></p>
            <p>redux-toolkit demo 异步<button onClick={() => { dispatch(asyncdecrement({ step: 1 })) }}>{count}</button></p>
        </>
    )
}

export default ReduxDemo

四、引入antd及修改antd默认主题

pnpm install antd less less-loader
  • 在main.tsx中引入antd默认样式
// src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import 'antd/dist/antd.less'; // 引入antd默认样式
import { Provider } from 'react-redux'
import store from './store/index'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
)
  • 修改主题
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  server: {
    open: true
  },
  resolve: { // 设置项目文件导入路径
    alias: [
      { find: '@', replacement: path.resolve(__dirname, './src') }
    ]
  },
  css: {
    preprocessorOptions: {
      less: {
        modifyVars: { // 更改主题在这里
          // 'primary-color': '#52c41a',
          // 'link-color': '#1DA57A',
          // 'border-radius-base': '2px'
        },
        javascriptEnabled: true
      }
    }
  }
})

以上代码已上传https://github.com/zjiafeng/vite-react

  • 2人 Love
  • 0人 Haha
  • 0人 Wow
  • 0人 Sad
  • 0人 Angry
Antd、React、Vite

作者简介: Jiafeng

共 0 条评论关于 “react+vite+ts+antd 搭建项目基础框架”

Loading...