Skip to content

创建项目

js
#vite
pnpm create vite@latest xxx --template react-ts
#webPack
npx create-react-app xxx

vite配置路径别名

  1. npm i @types/node -D 安装依赖

  2. vite.config.ts 配置

    ts
       import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react'
    import path from 'path' 
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [react()],
    // 配置以下内容
      resolve: {
        alias: {
          '@': path.resolve(__dirname, './src'),
        },
      },
    })
  3. tsconfig.json 添加内容

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

路由

路由初始化

  1. 安装 pnpm i react-router-dom

  2. 初始化路由 router/index.tsx

    jsx
    import { createBrowserRouter } from 'react-router-dom'
    import Home from '../pages/Home'
    import { Suspense, lazy } from 'react' #路由懒加载所需函数
    
    const Detail = lazy(() => import('../pages/Detail')) #路由懒加载
    const router = createBrowserRouter([
      {
        path: '/',
        element: <Home />
      },
      {
        path: '/detail/:id', #注意此处配置params传参
        element: (
            // 懒加载必须包裹
          <Suspense fallback={'加载中'}>   
            <Detail></Detail>
          </Suspense>
        )
      },
      {
        path: '*', #在末尾配置404
        element: <NotFound />
      },
    ])
    // 导出路由
    export default router
  3. 使用路由 main.tsx

    tsx
    import ReactDOM from 'react-dom/client'
    #// 导入Provider 必须要用RouterProvider
    import { RouterProvider } from 'react-router-dom'
    #// 导入router实例
    import router from './router/index.tsx'
    
    ReactDOM.createRoot(document.getElementById('root')!).render(
      <RouterProvider router={router} />
    )

嵌套路由

jsx
#配置时
{
    path: '/',
    element: <Layout />,
    children: [
      // 设置为默认二级路由 一级路由访问的时候,它也能得到渲染
      {
        index: true, // 设置为默认二级路由
        element: <Board />
      },
      {
        path: 'about',
        element: <About />
      }
    ]
  },
#Layout内使用 <Outlet />路由出口
const Layout = () => {
    return (
    <div>
        <div>我是Layout</div>
        <Outlet /> 
    </div>
    )
}

路由跳转&传参&参数获取方式

  • searchParams方式,获取用useSearchParams

  • params方式,获取用useParams

    tsx
    import { useNavigate } from 'react-router-dom'  
    import { useNavigate, useSearchParams, useParams } from 'react-router-dom'
     const navigate = useNavigate()
     const goDetail = (art_id: string) => () => {
           navigate(`/detail?id=${id}`)  #searchParams方式
           navigate(`/detail/${id}`) #params方式
         }
     #获取 searchParams 方式
     const [params] = useSearchParams()
     let id = params.get(id)
    #获取params方式
    const params = useParams()
    let id = params.id

Redux基本使用

安装工具包 pnpm i @reduxjs/toolkit react-redux

  1. store/modules/countStore.js 内对仓库进行定义

    js

import { createSlice } from '@reduxjs/toolkit'

const countStore = createSlice({ name: 'count', initialState: { count: 0, userInfo: {} }, reducers: { increment(state, action) { state.count += action.payload }, setUserInfo(state, action) { state.userInfo = action.payload } } }) // 解构函数 const { increment, setUserInfo } = countStore.actions

// 异步函数 发送请求 const getUserInfo = () => { return async (dispatch) => { const res = await fetch('http://geek.itheima.net/v1_0/channels') const data = await res.json() dispatch(setUserInfo(data.data.channels)) } } export { increment, getUserInfo } // 导出函数 export default countStore.reducer // 导出reducerstore/modules/countStore.ts 内对仓库进行定义


2. #### store/index.js 内进行导入仓库


```js
import { configureStore } from "@reduxjs/toolkit";
import countStore from "./modules/countStore";

const store = configureStore({
reducer: {
 counter:countStore // 前面counter定义的是什么,在项目中state.xxx就是什么
}
})
export default store;
  1. main.tsx 进行挂载仓库

tsx
import ReactDOM from 'react-dom/client'

// 导入Provider
import { RouterProvider } from 'react-router-dom'
// 导入router实例
import router from './router/index.tsx'
// 导入provider   用于提供store
import { Provider } from 'react-redux'
// 导入store
import store from './store/index.ts'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <Provider store={store}>
    <RouterProvider router={router} />
  </Provider>
)
  1. 在组件内使用仓库

tsx
import { useDispatch, useSelector } from 'react-redux'
import { getUserInfo, increment } from '@/store/modules/countStore'
import { useEffect } from 'react'
const Home = () => {
 // 解构出仓库中定义的数据  
  const { count } = useSelector((state: any) => state.counter)
  
  const dispatch = useDispatch() // 触发仓库中方法的函数
  
  const handleCount = () => {
    dispatch(increment(1))
  }
  
  // 上来就发送请求
  useEffect(() => {
    dispatch(getUserInfo())
  }, [dispatch]) // 注意此处传参
  return (
      <Button onClick={handleCount}>count++{count}</Button>
  )
}

export default Home

React组件灵活渲染

jsx
import { DetailRes, fetchDetailAPI } from '@/api/list'
import { NavBar } from 'antd-mobile'
import { useEffect, useState } from 'react'
import { useNavigate, useSearchParams } from 'react-router-dom'

const Detail = () => {
  const [detail, setDetail] = useState<DetailRes | null>(null)
  const navigate = useNavigate()
  const [params] = useSearchParams()
  const id = params.get('id')
  useEffect(() => {
    const getDetail = async () => {
      const res = await fetchDetailAPI(id!)
      setDetail(res.data.data)
    }
    getDetail()
  }, [id]) //id变化就会重新请求数据

  const back = () => {
    navigate(-1) // 返回
  }

  if (!detail) { //如果数据还没请求到
    return <div>this is Loading</div>
  } else {
    return (
      <div>
        <NavBar onBack={back}>{detail?.title}</NavBar>
            // 此处是渲染html格式的 v-html
        <div dangerouslySetInnerHTML={{ __html: detail?.content }}></div> 
      </div>
    )
  }
}

export default Detail

React简单登录校验

  1. 定义个token校验的组件 components/AuthRoute/index.jsx

jsx
import { Navigate } from 'react-router-dom'
import { getToken } from '../../utils/token'

export function AuthRoute({ children }) { // 此处实际传递的是子组件
  const token = getToken()  //获取token的方法
  if (token) { //如果有token
    return <>{children}</> //渲染子组件
  } else {
    return <Navigate to='/login' replace />
  }
}
  1. 在路由页面进行使用 对公共父组件Layout进行包裹

jsx
import { createBrowserRouter } from 'react-router-dom'
import Layout from '@/pages/Layout'
import Login from '@/pages/Login'
import { AuthRoute } from '../components/AuthRoute'
import { Suspense, lazy } from 'react'

const Home = lazy(() => import('@/pages/Home/index')) //懒加载
const Article = lazy(() => import('@/pages/Article'))
const Publish = lazy(() => import('@/pages/Publish'))
const router = createBrowserRouter([
  {
    path: '/',
    element: (
        // 进行包裹
      <AuthRoute>  
        <Layout />
      </AuthRoute>
    ),
    children: [
      {
        index: 1, // 默认首页
        element: (
            // 懒加载也必须进行包裹
          <Suspense fallback={'加载中'}>
            <Home></Home>
          </Suspense>
        )
      },
      {
        path: 'article',
        element: (
          <Suspense fallback={'加载中'}>
            <Article></Article>
          </Suspense>
        )
      }
    ]
  },
  {
    path: '/login',
    element: <Login />
  }
])
export default router