0
点赞
收藏
分享

微信扫一扫

我用 midjourney 创作的那些好看的图片

就是耍帅 2024-01-12 阅读 12

我们尝试使用recoil进行全局状态管理以及axios进行网络请求。

recoil

recoil是facebook官方推出的新的react状态管理方案,采用分散管理原子状态的设计模式,同时也强调immuteable(mobx则是mutable),这与react强调immuteable相符合,更好的适应react,增强组件整体性能。以下是官网的提出的动机:
如果只借助react实现全局状态管理,通过提升变量或者使用Context:

Recoil相比于redux、mobx的优势:

Recoil采用hook的方式获得或修改状态,同时也提供了派生状态,类似于computed

使用

在axios进行网络请求时,我们实现网络请求时的全局遮罩层加载,在axios的拦截器中统一实现而无需每一次请求都需要手动添加,提高代码的效率,减少不必要的重复工作。

此时就需要一个全局状态来管理遮罩层的隐藏与加载,在这里我们通过recoil实现。

使用npm安装axios及recoil

使用Recoil的组件需要使用RecoilRoot组件包裹起来,我们在main.tsx中引入RecoilRoot组件,然后将其包裹在根组件外

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import {MemoryRouter} from 'react-router-dom'
import {RecoilRoot} from 'recoil'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <MemoryRouter>
      <RecoilRoot>
      <App />
      </RecoilRoot>
    </MemoryRouter>
  </React.StrictMode>,
)

接着我们可以新建一个store文件夹,定义一个loading.ts文件

import { atom } from "recoil"

export const loadingState = atom({
  key: "loadingState",
  default: false,
})

recoil通过Atom定义一个状态,Atom 是一种新的状态,但是和传统的 state 不同,它可以被任何组件订阅,当一个 Atom 被更新时,每个被订阅的组件都会用新的值来重新渲染。

接着我们新建一个api文件夹,新建index.ts文件完成axios的配置,及loadingState的更新

import axios from "axios"
import { loadingState } from "@/store/loading"
import { useSetRecoilState } from "recoil"

axios.defaults.baseURL = "http://localhost:3000/api"
const setLoading = useSetRecoilState(loadingState)

// 请求拦截器
axios.interceptors.request.use((config) => {
  setLoading(true)
  //加入token或其他一些操作
  const token = localStorage.getItem("token")
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

// 相应拦截器
axios.interceptors.response.use((res) => {
  setLoading(false)
  return res
})


其中
useRecoilState:类似 useState 的一个 Hook,可以取到 atom 的值以及 setter 函数

useSetRecoilState:只获取 setter 函数,如果只使用了这个函数,状态变化不会导致组件重新渲染

useRecoilValue:只获取状态

loadingState控制app.tsx中的遮罩层及导航栏
在app.tsx中我们使用了MaskSpinLoading组件来实现加载效果,同时也控制导航栏,通过使用useRecoilValuehook得到的flag来控制。

import { Routes,Route,useNavigate,useLocation, Navigate  } from 'react-router-dom'
import { TabBar,Popup,Mask,SpinLoading} from 'antd-mobile'
import { tabs } from './router'
import  './App.css'
import {useRecoilValue} from 'recoil'
import {loadingState} from './store/loading'
function App() {
 const pathname = useLocation().pathname
 const navigate = useNavigate()
 const setRouteActive = (value: string) => {
  console.log(value)
  navigate(value,{state:'1'})
 }
 const flag = useRecoilValue<boolean>(loadingState)
 
 return (
  <>
      <Mask visible={flag} className='mask' >
        <SpinLoading />
      </Mask>
    <Routes>
      {tabs.map(item => (
        <Route key={item.key} path={item.key} element={item.element} />
      ))}
      <Route path='/' element={<Navigate to='/home'></Navigate>} />
      <Route path="*" element={<div>404</div>} />
    </Routes>
    <Popup visible={!flag} mask={false}>
    
    <TabBar activeKey={pathname} onChange={value => setRouteActive(value)}>
      {tabs.map(item => (
        <TabBar.Item key={item.key} icon={item.icon} title={item.title} />
      ))}
    </TabBar>
    </Popup>
  </>
 )
}

export default App

这里我们对之前的路由配置也进行了优化,对‘/’路径进行了重定向

 <Route path='/' element={<Navigate to='/home'></Navigate>} />

同样我们也可以在其他地方引入loadingState,比如在home.tsx中

import {Button } from 'antd-mobile'
import { loadingState } from '@/store/loading'
import {useRecoilState} from 'recoil'
export default function Home() {
    const [flag,setFlag] = useRecoilState<boolean>(loadingState)
    return (
        <div>
         <Button color='primary' onClick={()=>setFlag(!flag)}>change</Button>
        </div>
    )
}

点击按钮前
在这里插入图片描述
点击按钮后,flag状态被修改,遮罩层和loading出现
在这里插入图片描述

举报

相关推荐

0 条评论