likes
comments
collection
share

react入门(中)

作者站长头像
站长
· 阅读数 21

自定义hook

import { useState } from 'react'
// 把可复用的逻辑写在一个自定义的 hook 中,最后返回设定的值和方法,可以以数组或是对象的形式返回
const useToggle = () => {
  const [value, setValue] = useState(false)
  const toggle = () => setValue(!value)
  return [value, toggle]
}

const App = () => {
  // 使用自定义 hook
  // 调用 useToggle 返回的值和方法
  const [value, toggle] = useToggle()
  return (
    <div>
      <button onClick={toggle}>Toggle</button>
      <div>{value && 'Hello World'}</div>
    </div>
  )
}

export default App

状态管理

redux

react入门(中)

可以理解为vue中的vuex和pinia,进行集中式状态管理

redux toolkit 官方推荐redux逻辑的方式,是一套工具集,简化书写方式

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

react入门(中)

安装插件

pnpm i @reduxjs/toolkit react-redux

定义 store

// src/store/modules/user.tsx
import { createSlice } from '@reduxjs/toolkit';

// 创建一个包含初始状态、同步方法的 slice
const userSlice = createSlice({
  name: 'user',
  initialState: { token: '00002' },
  reducers: {
    setToken: (state, action) => {
      state.token = action.payload;
    },
    delToken: (state) => {
      state.token = '';
    },
  },
});

// 解构出创建 action 对象的函数
const { setToken, delToken } = userSlice.actions;

// 获取 reducer 函数
const userReducer = userSlice.reducer;

// 导出 action 和 reducer
export { setToken, delToken };
export default userReducer;

中转配置 store

// src/store/index.tsx
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './modules/user';

// 配置 Redux store
// 根 store 组装所有子模块 
const store = configureStore({
  reducer: {
    user: userReducer,
  },
});

export default store;

注入 store

# main.tsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import {RouterProvider} from 'react-router-dom'
import { Provider } from 'react-redux'
import store from './store'
import router from './router'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
   <Provider store={store}>
    <RouterProvider router={router} />
   </Provider>
  </React.StrictMode>
)

组件中使用store

import { useSelector, useDispatch } from 'react-redux'
import { setToken, delToken } from '../../store/modules/user'
function App() {
  const { token } = useSelector((state: any) => state.user)
  const dispatch = useDispatch()
  return (
    <>
      <span>{token}</span>
      <br />
      <button onClick={() => dispatch(setToken('123'))}>设置token</button>
      &nbsp;
      <button onClick={() => dispatch(delToken())}>删除token</button>
    </>
  )
}
export default App

Zustand

安装

pnpm i zustand

定义 store

// 从 zustand 库导入 create 函数,用于创建新的 store 实例
import { create } from 'zustand';

// 使用 create 函数创建一个新的 store 实例
const userStore = create((set) => {
  // 返回一个对象,作为 store 的初始状态和方法
  return {
    // store 的初始状态,token 被初始化为 '0002'
    token: '0002',
    
    // 定义一个方法 setToken,接收一个 payload 参数,并使用 set 函数更新 token 的值
    setToken: (payload) => set({ token: payload }),
    
    // 定义一个方法 delToken,不接收任何参数,调用后将 token 更新为空字符串 ''
    delToken: () => set({ token: '' })
  }
})

// 将 userStore 导出为默认导出,以便在其他模块中使用
export default userStore;

组件中使用

import userStore from '../../store/modules/user'
function App() {
  const { token, setToken, delToken } = userStore()
  return (
    <>
      <span>{token}</span>
      <br />
      <button onClick={() => setToken('123456')}>设置token</button>
      &nbsp;
      <button onClick={() => delToken()}>删除token</button>
    </>
  )
}
export default App

切片模式

待施工

Easy-peasy

建立在redux之上,看单词就能看出来,翻译过来就是非常简单,小菜一碟

直接上手,安装插件

pnpm i easy-peasy

我们在根目录新建一个store文件夹,再新建一个index.tsx对所有的状态进行中转,再新建一个modules对各自的状态进行管理

src/
|-- store/
|   |-- index.js
|   |-- modules/
|       |-- user.js
|-- App.js

action 用于定义同步状态

  • action 回调 中的两个参数 state, payload
  • 第一个参数 state 是当前数据的状态,可以直接修改来更新状态
  • 第二个参数 payload 是传递给 action 的数据

thunk 用于定义异步状态

  • thunk 回调 中有两个参数 actions, payload
  • 第一个参数 actions 是当前模块的 action,可以调用 action 来更新状态
  • 第二个参数 payload 是调用异步函数传递给 thunk 的数据

定义

# user.tsx

import { action, thunk } from 'easy-peasy'
import request from '@/utils/request'
// 定义 user 模块
const user = {
  token: '00002',
  setToken: action((state, payload) => {
    state.token = payload
  }),
  delToken: action(state => {
    state.token = ''
  }),
  getToken: thunk(async actions => {
    const { data } = await request.get('/get/token')
    actions.setToken(data)
  }),
}

export default user

中转

# index.tsx

import { createStore } from 'easy-peasy';
import user from './modules/user'

/**
* 在 index.tsx 中导入createStore 方法创建一个 store 实例
*/

// 组合所有模块
const storeModel = {
  user:user
}

// 创建 store 实例存储
const store=createStore(storeModel)

export default store;

组件中使用

useStoreStateuseStoreActions 都接收一个回调函数。这种方式允许你访问和使用 store 的状态或 actions,而不是直接暴露整个 store 对象。这样可以避免不必要的重新渲染,确保组件仅在相关状态或 actions 发生变化时才更新

import { useStoreState, useStoreActions } from 'easy-peasy' // 在要使用的组件中导入 useStoreState 和useStoreActions hook 来访问和操作 store 中的状态
const home = () => {
  const token = useStoreState((state)=> state.user.token)
  const setToken = useStoreActions((state)=> state.user.setToken)
  const delToken = useStoreActions((state)=> state.user.delToken)
  return (
    <>
    <div>{token}</div>
      <button onClick={()=>setToken('123456')}>设置token</button>
      <br />
      <button onClick={()=>delToken()}>清除token</button>
    </>
  )
}

export default home

react入门(中)

ReactRouter

安装 react-router-dom 包

pnpm i react-router-dom
import React from 'react'
import ReactDOM from 'react-dom/client'
import { RouterProvider } from 'react-router-dom' // 引入路由组件
import  router  from './router' // 引入路由实例

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <RouterProvider router={router}></RouterProvider>   RouterProvider 用来提供路由出口并绑定路由
  </React.StrictMode>
)

配置路由信息

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

import Home from '../pages/home'
import Article from '../pages/article'

创建路由实例对象

const router = createBrowserRouter([
  {
    path: '/',
    element: <Home />, // element 表示要渲染的组件 ,就是 vue 中的component
  },
  {
    path: '/article',
    element: <Article />,
  },
])
// 导出路由实例对象
export default router

路由跳转

编程式导航

使用 useNavigate 可以理解为 vue 中的 router.push()方法

import { Link , useNavigate} from "react-router-dom"

const Home = () => {
   const navigate = useNavigate()
  return (
    <div>
      <Link to={"/article"}>article</Link>
      <h1>home</h1>
      <button onClick={() => navigate('/article')}>去文章页面</button>
    </div>
  )
}
export default Home

声明式导航

使用 Link 标签 to 属性后为跳转的路径地址,在实际渲染时会被渲染为 html 的 a 标签

import { Link } from "react-router-dom"

const Home = () => {
  return (
    <div>
      <Link to={"/article"}>article</Link>
      <h1>home</h1>
    </div>
  )
}
export default Home

路由传参

searchParams传参

// 首页
import { useNavigate, Link } from 'react-router-dom'

const home = () => {
  const navigate = useNavigate()
  return (
    <div>
      <h1>Home</h1>
      <button onClick={() => navigate('/article?id=1001&name=react')}>去文章页</button>
    </div>
  )
}

export default home
// 详情页
import { Link } from 'react-router-dom'
import { useSearchParams } from 'react-router-dom'
// 使用了useSearchParams钩子来获取URL中的查询参数。useSearchParams返回一个数组,其中第一个元素是SearchParams对象,第二个元素是一个函数,用于更新查询参数
const Article = () => {
  const [params] = useSearchParams()
  const id = params.get('id') // 通过get方法获取参数
  const name = params.get('name')
  return (
    <div>
      <Link to='/home'>回到首页</Link>
      <h1>article</h1>
      <p>id:{id}--name:{name}</p>
    </div>
  )
}
export default Article

params传参

// 首页
import { useNavigate, Link } from 'react-router-dom'

const home = () => {
  const navigate = useNavigate()
  return (
    <div>
      <h1>Home</h1>
      <button onClick={() => navigate('/article/1002/react')}>去文章页</button>
    </div>
  )
}

export default home

去到路由的位置,加上占位符

const router = createBrowserRouter([
    { path: '/article/:id/:tile', element: <Article /> }
])

详情页

import { Link,useParams } from 'react-router-dom'
const Article = () => {
  const params = useParams()
  const id = params.id // params 是通过.语法来获取传递的参数
  const name = params.name
  return (
    <div>
      <Link to='/home'>回到首页</Link>
      <h1>article</h1>
      <p>id:{id}----name:{name}</p>
    </div>
  )
}
export default Article

嵌套路由

使用children表示对应的二级路由地址

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

import Home from '../pages/home'
import Article from '../pages/article'
// 创建路由实例对象
const router = createBrowserRouter([
  {
    path: '/',
    element: <Home />, // element 表示要渲染的组件 ,就是 vue 中的component
    children: [
      {
        path: 'article',
        element: <Article />,
      }
    ]
  },

])
// 导出路由实例对象
export default router

在要渲染二级路由的地方,放置 Outlet 标签,和vue中的 view-router 是一个意思

import { Link , Outlet} from "react-router-dom" // outlet 表示占位符,表示二级路由的渲染位置
const Home = () => {
  return (
    <div>
      <Link to='/article'>article</Link>
      <h1>home</h1>
      <Outlet/>
    </div>
  )
}
export default Home

默认显示二级路由

去掉二级路由的 path 属性替换为 index:true

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

import Home from '../pages/home'
import Article from '../pages/article'
// 创建路由实例对象
const router = createBrowserRouter([
  {
    path: '/',
    element: <Home />, // element 表示要渲染的组件 ,就是 vue 中的component
    children: [
      {
        index: true, // index 表示当前路由是默认路由
        element: <Article />,
      }
    ]
  },

])
// 导出路由实例对象
export default router

404 页面配置

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

import Home from '../pages/home'
import Article from '../pages/article'
// 创建路由实例对象
const router = createBrowserRouter([
  {
    path: '/',
    element: <Home />, // element 表示要渲染的组件 ,就是 vue 中的component
    children: [
      {
        index: true, // index 表示当前路由是默认路由
        element: <Article />,
      }
    ]
  },
  {
    path: '*',
    element: <div>404</div> // 表示 404 页面
  }

])
// 导出路由实例对象
export default router

路由懒加载

  1. 使用 react 内置的lazy函数实现路由懒加载
  2. Suspense 组件包裹路由中element选项对应的组件
import { createBrowserRouter } from 'react-router-dom'
import { lazy, Suspense } from 'react'

const Detail = lazy(() => import('../pages/detail/index'))
const Home = lazy(() => import('../pages/home/index'))

const router = createBrowserRouter([
  {
    path: '/',
    element: (
      <Suspense>
        <Home />
      </Suspense>
    ),
    children: [
      {
        path: 'detail',
        element: (
          <Suspense>
            <Detail />
          </Suspense>
        ),
      },
    ],
  }
])

export default router
转载自:https://juejin.cn/post/7396361501730914342
评论
请登录