-
Notifications
You must be signed in to change notification settings - Fork 0
/
36e87c18.html
1 lines (1 loc) · 264 KB
/
36e87c18.html
1
<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><title>React17+React Hook+TS4 最佳实践仿 Jira 企业级项目笔记 | 梦洁小站-属于你我的小天地</title><meta name="author" content="梦洁"><meta name="copyright" content="梦洁"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="前言 个人笔记,记录个人过程,如有不对,敬请指出 React17+React Hook+TS4 最佳实践仿 Jira 企业级项目项目完成到第十章,剩下后面就没有看了,说的不是特别好 github地址:https://github.com/superBiuBiuMan/React-jira husky方便我们管理git hooks的工具 REST-API风格https://zhuanlan."><meta property="og:type" content="article"><meta property="og:title" content="React17+React Hook+TS4 最佳实践仿 Jira 企业级项目笔记"><meta property="og:url" content="https://www.dreamlove.top/36e87c18.html"><meta property="og:site_name" content="梦洁小站-属于你我的小天地"><meta property="og:description" content="前言 个人笔记,记录个人过程,如有不对,敬请指出 React17+React Hook+TS4 最佳实践仿 Jira 企业级项目项目完成到第十章,剩下后面就没有看了,说的不是特别好 github地址:https://github.com/superBiuBiuMan/React-jira husky方便我们管理git hooks的工具 REST-API风格https://zhuanlan."><meta property="og:locale" content="zh_CN"><meta property="og:image" content="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202304091759286.png"><meta property="article:published_time" content="2023-03-08T09:25:46.000Z"><meta property="article:modified_time" content="2023-03-08T09:25:46.000Z"><meta property="article:author" content="梦洁"><meta property="article:tag" content="React"><meta name="twitter:card" content="summary"><meta name="twitter:image" content="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202304091759286.png"><link rel="shortcut icon" href="https://oss.dreamlove.top/i/2024/02/02/nw24wu.png"><link rel="canonical" href="https://www.dreamlove.top/36e87c18.html"><link rel="preconnect" href="https://lib.baomitu.com"><link rel="preconnect" href="//busuanzi.ibruce.info"><link rel="stylesheet" href="/css/index.css?v=4.13.0"><link rel="stylesheet" href="https://lib.baomitu.com/font-awesome/6.5.1/css/all.min.css"><link rel="stylesheet" href="https://lib.baomitu.com/fancyapps-ui/5.0.33/fancybox/fancybox.min.css" media="print" onload='this.media="all"'><script>const GLOBAL_CONFIG={root:"/",algolia:{appId:"G7A2D1SYPY",apiKey:"49056313a9be02852c7dbedfcb772831",indexName:"blog",hits:{per_page:20},languages:{input_placeholder:"搜索文章",hits_empty:"找不到您查询的内容:${query}",hits_stats:"找到 ${hits} 条结果,用时 ${time} 毫秒"}},localSearch:void 0,translate:void 0,noticeOutdate:void 0,highlight:{plugin:"highlight.js",highlightCopy:!0,highlightLang:!0,highlightHeightLimit:!1},copy:{success:"复制成功",error:"复制错误",noSupport:"浏览器不支持"},relativeDate:{homepage:!1,post:!1},runtime:"天",dateSuffix:{just:"刚刚",min:"分钟前",hour:"小时前",day:"天前",month:"个月前"},copyright:void 0,lightbox:"fancybox",Snackbar:void 0,infinitegrid:{js:"https://lib.baomitu.com/egjs-infinitegrid/4.11.1/infinitegrid.min.js",buttonText:"加载更多"},isPhotoFigcaption:!1,islazyload:!1,isAnchor:!1,percent:{toc:!0,rightside:!1},autoDarkmode:!1}</script><script id="config-diff">var GLOBAL_CONFIG_SITE={title:"React17+React Hook+TS4 最佳实践仿 Jira 企业级项目笔记",isPost:!0,isHome:!1,isHighlightShrink:!1,isToc:!0,postUpdate:"2023-03-08 09:25:46"}</script><script>(e=>{e.saveToLocal={set:(e,t,o)=>{if(0===o)return;const a={value:t,expiry:Date.now()+864e5*o};localStorage.setItem(e,JSON.stringify(a))},get:e=>{const t=localStorage.getItem(e);if(!t)return;const o=JSON.parse(t);if(!(Date.now()>o.expiry))return o.value;localStorage.removeItem(e)}},e.getScript=(e,t={})=>new Promise((o,a)=>{const n=document.createElement("script");n.src=e,n.async=!0,n.onerror=a,n.onload=n.onreadystatechange=function(){const e=this.readyState;e&&"loaded"!==e&&"complete"!==e||(n.onload=n.onreadystatechange=null,o())},Object.keys(t).forEach(e=>{n.setAttribute(e,t[e])}),document.head.appendChild(n)}),e.getCSS=(e,t=!1)=>new Promise((o,a)=>{const n=document.createElement("link");n.rel="stylesheet",n.href=e,t&&(n.id=t),n.onerror=a,n.onload=n.onreadystatechange=function(){const e=this.readyState;e&&"loaded"!==e&&"complete"!==e||(n.onload=n.onreadystatechange=null,o())},document.head.appendChild(n)}),e.activateDarkMode=()=>{document.documentElement.setAttribute("data-theme","dark"),null!==document.querySelector('meta[name="theme-color"]')&&document.querySelector('meta[name="theme-color"]').setAttribute("content","#0d0d0d")},e.activateLightMode=()=>{document.documentElement.setAttribute("data-theme","light"),null!==document.querySelector('meta[name="theme-color"]')&&document.querySelector('meta[name="theme-color"]').setAttribute("content","#ffffff")};const t=saveToLocal.get("theme");"dark"===t?activateDarkMode():"light"===t&&activateLightMode();const o=saveToLocal.get("aside-status");void 0!==o&&("hide"===o?document.documentElement.classList.add("hide-aside"):document.documentElement.classList.remove("hide-aside"));/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)&&document.documentElement.classList.add("apple")})(window)</script><meta name="generator" content="Hexo 7.1.1"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://oss.dreamlove.top/i/2024/02/02/nw24wu.png" onerror='onerror=null,src="/img/404.png"' alt="avatar"></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">168</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">90</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">68</div></a></div><hr class="custom-hr"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友情和链接</span></a></div><div class="menus_item"><a class="site-page" href="/navigation/"><i class="fa-fw fas fa-link"></i><span> 链接导航</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 私有化导航</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" target="_blank" rel="noopener" href="https://mark.123916.xyz/"><i class="fa-fw fas fa-database"></i><span> 导航</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://cloud.reassurehome.com/"><i class="fa-fw fas fa-hippo"></i><span> Alist(私有)</span></a></li></ul></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 工具</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" target="_blank" rel="noopener" href="https://short.123916.xyz/027a2"><i class="fa-fw fas fa-paperclip"></i><span> clash免费订阅地址</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://short.123916.xyz/admin/"><i class="fa-fw fas fa-paperclip"></i><span> 短链接生成</span></a></li></ul></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 好玩的</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" target="_blank" rel="noopener" href="https://make.girls.moe/#/"><i class="fa-fw fas fa-database"></i><span> 动漫头像制作</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="http://dfqshy.ysepan.com/"><i class="fa-fw fas fa-database"></i><span> FC游戏大全网盘</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://www.yikm.net/"><i class="fa-fw fas fa-database"></i><span> 小霸王</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://www.return8090.com/"><i class="fa-fw fas fa-database"></i><span> 小霸王(广告多)</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="http://farm.dreamlove.top"><i class="fa-fw fas fa-database"></i><span> QQ农场经典版</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://codepip.com/"><i class="fa-fw fas fa-database"></i><span> CssGame</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://photo.123916.xyz/"><i class="fa-fw fas fa-database"></i><span> 有趣的照片</span></a></li></ul></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 其他</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></li><li><a class="site-page child" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://buy.dreamlove.top/"><i class="fa-fw fas fa-heart"></i><span> 购物</span></a></li></ul></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image:url(https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202304091759286.png)"><nav id="nav"><span id="blog-info"><a href="/" title="梦洁小站-属于你我的小天地"><span class="site-name">梦洁小站-属于你我的小天地</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友情和链接</span></a></div><div class="menus_item"><a class="site-page" href="/navigation/"><i class="fa-fw fas fa-link"></i><span> 链接导航</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 私有化导航</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" target="_blank" rel="noopener" href="https://mark.123916.xyz/"><i class="fa-fw fas fa-database"></i><span> 导航</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://cloud.reassurehome.com/"><i class="fa-fw fas fa-hippo"></i><span> Alist(私有)</span></a></li></ul></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 工具</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" target="_blank" rel="noopener" href="https://short.123916.xyz/027a2"><i class="fa-fw fas fa-paperclip"></i><span> clash免费订阅地址</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://short.123916.xyz/admin/"><i class="fa-fw fas fa-paperclip"></i><span> 短链接生成</span></a></li></ul></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 好玩的</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" target="_blank" rel="noopener" href="https://make.girls.moe/#/"><i class="fa-fw fas fa-database"></i><span> 动漫头像制作</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="http://dfqshy.ysepan.com/"><i class="fa-fw fas fa-database"></i><span> FC游戏大全网盘</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://www.yikm.net/"><i class="fa-fw fas fa-database"></i><span> 小霸王</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://www.return8090.com/"><i class="fa-fw fas fa-database"></i><span> 小霸王(广告多)</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="http://farm.dreamlove.top"><i class="fa-fw fas fa-database"></i><span> QQ农场经典版</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://codepip.com/"><i class="fa-fw fas fa-database"></i><span> CssGame</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://photo.123916.xyz/"><i class="fa-fw fas fa-database"></i><span> 有趣的照片</span></a></li></ul></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 其他</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></li><li><a class="site-page child" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></li><li><a class="site-page child" target="_blank" rel="noopener" href="https://buy.dreamlove.top/"><i class="fa-fw fas fa-heart"></i><span> 购物</span></a></li></ul></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">React17+React Hook+TS4 最佳实践仿 Jira 企业级项目笔记</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2023-03-08T09:25:46.000Z" title="发表于 2023-03-08 09:25:46">2023-03-08</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-08T09:25:46.000Z" title="更新于 2023-03-08 09:25:46">2023-03-08</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/React/">React</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">11.6k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>50分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" data-flag-title="React17+React Hook+TS4 最佳实践仿 Jira 企业级项目笔记"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><ul><li>个人笔记,记录个人过程,如有不对,敬请指出</li><li>React17+React Hook+TS4 最佳实践仿 Jira 企业级项目项目<strong>完成到第十章</strong>,剩下后面就没有看了,说的不是特别好<ul><li>github地址:<a target="_blank" rel="noopener" href="https://github.com/superBiuBiuMan/React-jira">https://github.com/superBiuBiuMan/React-jira</a></li></ul></li><li>husky方便我们管理git hooks的工具</li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202212032040316.png" alt="image-20221203204054233"></p><h2 id="REST-API风格"><a href="#REST-API风格" class="headerlink" title="REST-API风格"></a>REST-API风格</h2><p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/536437382">https://zhuanlan.zhihu.com/p/536437382</a></p><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202212041750444.png"></p><h2 id="json-server"><a href="#json-server" class="headerlink" title="json-server"></a>json-server</h2><ul><li>安装</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g json-server</span><br></pre></td></tr></table></figure><ul><li>项目安装</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -D json-server </span><br></pre></td></tr></table></figure><h1 id="项目开始"><a href="#项目开始" class="headerlink" title="项目开始"></a>项目开始</h1><h2 id="用jsx渲染开发工程列表"><a href="#用jsx渲染开发工程列表" class="headerlink" title="用jsx渲染开发工程列表"></a>用jsx渲染开发工程列表</h2><ul><li>初始化代码出现问题,表单收集的组件无法将请求结果发送给list组件</li></ul><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, { useEffect, useState } <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">List</span> = (<span class="params"></span>) => {</span><br><span class="line"> <span class="keyword">const</span> [params,setParams] = <span class="title function_">useState</span>({</span><br><span class="line"> <span class="attr">name</span>:<span class="string">''</span>,</span><br><span class="line"> <span class="attr">personId</span>:<span class="string">''</span>,</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">const</span> [selectOptions,setSelectOptions] = <span class="title function_">useState</span>([])</span><br><span class="line"> <span class="keyword">const</span> [listData,setListData] = <span class="title function_">useState</span>([]) <span class="comment">//请求列表数据</span></span><br><span class="line"> <span class="title function_">useEffect</span>(<span class="keyword">async</span> () => {</span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> <span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">'/abc'</span>);</span><br><span class="line"> <span class="keyword">if</span>(response.<span class="property">ok</span>){</span><br><span class="line"> <span class="keyword">const</span> result = <span class="keyword">await</span> response.<span class="title function_">json</span>();<span class="comment">//获取数据结果</span></span><br><span class="line"> <span class="title function_">setListData</span>(result ?? [])</span><br><span class="line"> }</span><br><span class="line"> }<span class="keyword">catch</span> (e){</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'发生错误'</span>);</span><br><span class="line"> }</span><br><span class="line"> },[params])</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">form</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">'text'</span> <span class="attr">value</span>=<span class="string">{params.name}</span> <span class="attr">onChange</span>=<span class="string">{event</span> =></span> setParams({ ...params,name:event.target.value })}/></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">select</span> <span class="attr">value</span>=<span class="string">{params.personId}</span> <span class="attr">onChange</span>=<span class="string">{event</span> =></span> setParams({</span></span><br><span class="line"><span class="language-xml"> ...params,</span></span><br><span class="line"><span class="language-xml"> personId: event.target.value,</span></span><br><span class="line"><span class="language-xml"> })}></span></span><br><span class="line"><span class="language-xml"> {</span></span><br><span class="line"><span class="language-xml"> selectOptions.map(item => {</span></span><br><span class="line"><span class="language-xml"> return (</span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">option</span> <span class="attr">value</span>=<span class="string">{item.value}</span>></span>{ item.label }<span class="tag"></<span class="name">option</span>></span></span></span><br><span class="line"><span class="language-xml"> )</span></span><br><span class="line"><span class="language-xml"> })</span></span><br><span class="line"><span class="language-xml"> }</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">select</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">form</span>></span></span></span><br><span class="line"> );</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">List</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>解决办法(3-2 用状态提升分享组件状态,完成工程列表页面),也就是将请求放在父组件当中</li><li>顺带一提,如果我们使用的是<code>vite</code>创建的react项目,就无法像老师一样直接使用<code>process.env</code>来读取设置的变量了</li></ul><h2 id="学习自定义hook"><a href="#学习自定义hook" class="headerlink" title="学习自定义hook"></a>学习自定义hook</h2><ul><li><strong>useHooks(不管是自带的hooks还是自己创建的hooks),不可以在普通函数中运行,只能在hooks当中使用或者其他hooks使用,所以在自定义hooks的时候,需要以useXxx开头</strong></li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202301101959551.png"></p><h3 id="使用自定义的useMount和useDebounce"><a href="#使用自定义的useMount和useDebounce" class="headerlink" title="使用自定义的useMount和useDebounce"></a>使用自定义的useMount和useDebounce</h3><ul><li>useMount</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*只在初次挂载执行*/</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useMount</span> = (<span class="params">callback</span>) => {</span><br><span class="line"> <span class="title function_">useEffect</span>(callback,[])</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>useDebounce(防抖)</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*自定义防抖hooks*/</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useDebounce</span> = (<span class="params">value,delay</span>) => {</span><br><span class="line"> <span class="keyword">const</span> [debounceValue,setDebounceValue] = <span class="title function_">useState</span>(value)</span><br><span class="line"> <span class="title function_">useEffect</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">const</span> timer = <span class="built_in">setTimeout</span>(<span class="function">() =></span> { <span class="title function_">setDebounceValue</span>(value) },delay);</span><br><span class="line"> <span class="keyword">return</span> <span class="function">() =></span> {</span><br><span class="line"> <span class="comment">/*下一次effect执行前的处理*/</span></span><br><span class="line"> <span class="built_in">clearTimeout</span>(timer)</span><br><span class="line"> }</span><br><span class="line"> },[value,delay])</span><br><span class="line"> <span class="keyword">return</span> debounceValue;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>useDebounce的使用</li></ul><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*搜索参数*/</span></span><br><span class="line"><span class="keyword">const</span> [params,setParams] = <span class="title function_">useState</span>({</span><br><span class="line"> <span class="attr">name</span>:<span class="string">''</span>,</span><br><span class="line"> <span class="attr">personId</span>:<span class="string">''</span>,</span><br><span class="line">})</span><br><span class="line"><span class="keyword">const</span> debounceValue = <span class="title function_">useDebounce</span>(params,<span class="number">2000</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 当搜索条件发生变化的时候,就更新</span></span><br><span class="line"><span class="comment"> * */</span></span><br><span class="line"><span class="title function_">useEffect</span>(<span class="keyword">async</span> () => {</span><br><span class="line"> <span class="comment">/*请求获取列表数据*/</span></span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> <span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">`<span class="subst">${apiUrl}</span>/projects?<span class="subst">${qs.stringify(cleanEmptyObj(debounceValue))}</span>`</span>)</span><br><span class="line"> <span class="keyword">if</span>(response.<span class="property">ok</span>){</span><br><span class="line"> <span class="keyword">const</span> result = <span class="keyword">await</span> response.<span class="title function_">json</span>();</span><br><span class="line"> <span class="title function_">setListData</span>(result)</span><br><span class="line"> }</span><br><span class="line"> }<span class="keyword">catch</span> (e){</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(e);</span><br><span class="line"> }</span><br><span class="line">},[debounceValue])</span><br></pre></td></tr></table></figure><ul><li><p>useDebounce的理解</p><ul><li><p>传入: 传入需要节流的值和延迟</p></li><li><p>返回: 返回节流后的新state数据</p></li><li><p>原理:</p><ul><li>内部对传入的value进行重新构建一个<code>state</code>,当传入的value发生改变的时候的时候,会被内部debounce创建的节流函数所捕捉,捕捉到后,如果中途没有重新捕捉到新的值,则会在设置的时间之后更新内部debounce的值,否则的话就会中断更新,重新计时</li></ul></li><li><p>图示原理</p></li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202301102048930.png"></p></li></ul><h3 id="js改造为ts"><a href="#js改造为ts" class="headerlink" title="js改造为ts"></a>js改造为ts</h3><ul><li><p>文件名更改</p><ul><li>js -> 改为 ts</li><li>jsx -> 改为tsx</li></ul></li><li><p>遇到qs模块types缺失的情况<code>: Could not find a declaration file for module 'qs'.xxxx,npm i --save-dev @types/qs</code>,安装对应的types即可</p></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add @types/qs -D </span><br></pre></td></tr></table></figure><ul><li>注意箭头函数和普通函数的泛型书写位置</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">// 箭头函数</span><br><span class="line">const fn1 = <T,U>() => {</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">//普通函数</span><br><span class="line">function fn2<T,U>() {</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="鸭子类型和json-server中间件"><a href="#鸭子类型和json-server中间件" class="headerlink" title="鸭子类型和json-server中间件"></a>鸭子类型和json-server中间件</h2><ul><li>鸭子类型<ul><li>ts是只看是否实现了这个接口当中的成员,实现了就可以通过,没有实现就不通过,不管有没有定义</li><li>说通俗点就是只要你符合这个规定里面的规则,就是他说的一个东西</li><li>比如鸭子会嘎嘎叫,只要你会嘎嘎叫,ts就认为你是鸭子</li></ul></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Base</span> {</span><br><span class="line"> <span class="attr">id</span>:<span class="built_in">number</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">test</span> = (<span class="params">param:Base</span>) => {</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"><span class="comment">/*定义一个对象,对象当中的实现了接口Base的成员*/</span></span><br><span class="line"><span class="keyword">const</span> a = {</span><br><span class="line"> <span class="attr">id</span>:<span class="number">100</span>,</span><br><span class="line"> <span class="attr">name</span>:<span class="string">'李白'</span></span><br><span class="line">}</span><br><span class="line"><span class="title function_">test</span>(a);<span class="comment">//不会报错</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*定义一个对象,对象当中没有实现Base的成员*/</span></span><br><span class="line"><span class="keyword">const</span> b = {</span><br><span class="line"> <span class="attr">name</span>:<span class="string">'李白'</span></span><br><span class="line">}</span><br><span class="line"><span class="title function_">test</span>(b);<span class="comment">//警告 'id' is declared here.</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>json-server中间件<ul><li><strong>注意POST为大写</strong></li><li>package.json更改<code>"json-server": "json-server __json_server_mock/db.json --watch --port 3033 --middlewares __json_server_mock/middleware.js"</code></li></ul></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="function">(<span class="params">req,res,next</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span>(req.<span class="property">method</span> === <span class="string">'POST'</span> && req.<span class="property">path</span> === <span class="string">'/login'</span>){</span><br><span class="line"> <span class="keyword">if</span>(req.<span class="property">body</span>.<span class="property">username</span> === <span class="string">'qiuye'</span> && req.<span class="property">body</span>.<span class="property">password</span> === <span class="string">'123456'</span>){</span><br><span class="line"> <span class="keyword">return</span> res.<span class="title function_">status</span>(<span class="number">200</span>).<span class="title function_">json</span>({</span><br><span class="line"> <span class="attr">user</span>:{</span><br><span class="line"> <span class="attr">token</span>:<span class="string">'我是token'</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/*密码错误*/</span></span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> <span class="keyword">return</span> res.<span class="title function_">status</span>(<span class="number">400</span>).<span class="title function_">json</span>({<span class="attr">message</span>:<span class="string">'用户名或密码错误'</span>})</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="title function_">next</span>();</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>登录表单</li></ul><figure class="highlight tsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, { <span class="title class_">FormEvent</span> } <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"><span class="keyword">const</span> apiUrl = <span class="keyword">import</span>.<span class="property">meta</span>.<span class="property">env</span>.<span class="property">VITE_REACT_APP_API_URL</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">Login</span> = (<span class="params"></span>) => {</span><br><span class="line"> <span class="keyword">const</span> <span class="title function_">login</span> = (<span class="params">params:{username:<span class="built_in">string</span>,password:<span class="built_in">string</span>}</span>) => {</span><br><span class="line"> <span class="title function_">fetch</span>(<span class="string">`<span class="subst">${apiUrl}</span>/login`</span>,{</span><br><span class="line"> <span class="attr">method</span>:<span class="string">'POST'</span>,</span><br><span class="line"> <span class="attr">headers</span>:{</span><br><span class="line"> <span class="string">'Content-Type'</span>:<span class="string">'application/json'</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">body</span>:<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(params),</span><br><span class="line"> }).<span class="title function_">then</span>(<span class="keyword">async</span> (response) =>{</span><br><span class="line"> <span class="keyword">if</span>(response.<span class="property">ok</span>){</span><br><span class="line"> <span class="comment">//await response.json();</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">/*点击登录*/</span></span><br><span class="line"> <span class="keyword">const</span> <span class="title function_">handleSubmit</span> = (<span class="params">event:FormEvent</span>) => {</span><br><span class="line"> event.<span class="title function_">preventDefault</span>();<span class="comment">//阻止默认行为</span></span><br><span class="line"> <span class="comment">//@ts-ignore;</span></span><br><span class="line"> <span class="keyword">const</span> username = event.<span class="property">target</span>[<span class="number">0</span>].<span class="property">value</span>;</span><br><span class="line"> <span class="comment">//@ts-ignore;</span></span><br><span class="line"> <span class="keyword">const</span> password = event.<span class="property">target</span>[<span class="number">1</span>].<span class="property">value</span>;</span><br><span class="line"> <span class="title function_">login</span>({username,password})</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">form</span> <span class="attr">onSubmit</span>=<span class="string">{handleSubmit}</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">label</span> <span class="attr">htmlFor</span>=<span class="string">'username'</span>></span>用户名<span class="tag"></<span class="name">label</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">'text'</span> <span class="attr">id</span>=<span class="string">'username'</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">br</span>/></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">label</span> <span class="attr">htmlFor</span>=<span class="string">'password'</span>></span>密码<span class="tag"></<span class="name">label</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">'password'</span> <span class="attr">id</span>=<span class="string">'password'</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span> <span class="attr">type</span>=<span class="string">'submit'</span>></span>登录<span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">form</span>></span></span></span><br><span class="line"> );</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">Login</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="安装jira-dev-tool"><a href="#安装jira-dev-tool" class="headerlink" title="安装jira-dev-tool"></a>安装jira-dev-tool</h2><ul><li><p>npm地址:<a target="_blank" rel="noopener" href="https://www.npmjs.com/package/jira-dev-tool">https://www.npmjs.com/package/jira-dev-tool</a></p></li><li><p>如果安装后项目启动数据库连接失败,可以试试运行这个命令</p></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">npx msw init public</span><br><span class="line">//或者 指定到public目录下</span><br><span class="line">npx msw init ./public</span><br></pre></td></tr></table></figure><h2 id="使用自定义useHttp处理登录状态"><a href="#使用自定义useHttp处理登录状态" class="headerlink" title="使用自定义useHttp处理登录状态"></a>使用自定义useHttp处理登录状态</h2><ul><li><p>关于<code>Parameters</code>的使用,可以看看ts官方示例<a target="_blank" rel="noopener" href="https://www.typescriptlang.org/docs/handbook/utility-types.html">https://www.typescriptlang.org/docs/handbook/utility-types.html</a></p></li><li><p>所以老师当中的这个是什么意思呢?</p></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useHttp</span> = (<span class="params"></span>) => {</span><br><span class="line"> <span class="keyword">const</span> {userInfo} = <span class="title function_">useAuth</span>();</span><br><span class="line"> <span class="keyword">return</span> <span class="function">(<span class="params">...[url,config]:Parameters<<span class="keyword">typeof</span> http></span>) =></span> <span class="title function_">http</span>(url,{...config,<span class="attr">token</span>:userInfo.<span class="property">token</span>});</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 第一步:</span></span><br><span class="line">parameters<<span class="keyword">typeof</span> http>返回htpp的联合类型元组,也就是[<span class="attr">url</span>:string,{data,token,headers,...customConfig}:<span class="title class_">Config</span>]</span><br><span class="line"> <span class="comment">//所以你明白老师为什么要设置为一个数组了吧?因为这个是联合类型元组,描述的是数组的结构</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 第二步:使用扩展运算符展开函数参数</span></span><br><span class="line"> <span class="comment">//如果不适用展开运算符,我们调用函数必须要 Example(['请求地址',config对象])</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//如果使用了,就可以 Example('请求地址',config对象)</span></span><br></pre></td></tr></table></figure><ul><li>在使用函数的时候,如果是数组,想要将数组当中的数据依次传入数组,可以使用扩展运算符</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> arr1 = [<span class="number">1</span>, -<span class="number">1</span>, <span class="number">0</span>, <span class="number">5</span>, <span class="number">3</span>];</span><br><span class="line"><span class="keyword">const</span> min = <span class="title class_">Math</span>.<span class="title function_">min</span>(...arr1);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(min);<span class="comment">// -1 </span></span><br><span class="line"></span><br><span class="line"><span class="title class_">Math</span>.<span class="property">min</span>用法是传入<span class="number">0</span>个或多个数字,<span class="number">0</span> 个或多个数字,将在其中选择,并返回最小值。</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> arr1 = [<span class="number">1</span>, -<span class="number">1</span>, <span class="number">0</span>, <span class="number">5</span>, <span class="number">3</span>];</span><br><span class="line"><span class="keyword">const</span> max = <span class="title class_">Math</span>.<span class="title function_">max</span>(...arr1);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(max);<span class="comment">// 5</span></span><br><span class="line"><span class="title class_">Math</span>.<span class="property">max</span>用法是传入<span class="number">0</span>个或多个数字,<span class="number">0</span> 个或多个数字,将在其中选择,并返回最大值。</span><br></pre></td></tr></table></figure><h2 id="更改为antd"><a href="#更改为antd" class="headerlink" title="更改为antd"></a>更改为antd</h2><ul><li>表格排序的知识<ul><li><code>localeCompare</code>:<a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare">https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare</a></li></ul></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">string.localeCompare(targetString,locales,options);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">该方法返回的是一个数字用来表示一个参考字符串和对比字符串是排序在前,在后或者相同</span><br><span class="line"></span><br><span class="line">返回值:返回值是一个数字,目前的主流浏览器都返回的是1、0、-1三个值,但是也有其他情况,所以不可以用绝对的值等于1、-1这种去判断返回的结果</span><br><span class="line"></span><br><span class="line">返回值大于0:说明当前字符串string大于对比字符串targetString</span><br><span class="line"></span><br><span class="line">返回值小于0:说明当前字符串string小于对比字符串targetString</span><br><span class="line"></span><br><span class="line">返回值等于0:说明当前字符串string等于对比字符串targetString</span><br></pre></td></tr></table></figure><h2 id="使用css-in-js-Emotion"><a href="#使用css-in-js-Emotion" class="headerlink" title="使用css-in-js-Emotion"></a>使用css-in-js-Emotion</h2><ul><li>App.css样式更改为如下(App.css为全局样式)</li></ul><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">html</span>{</span><br><span class="line"> <span class="comment">/*使得1rem === 10px*/</span></span><br><span class="line"> <span class="attribute">font-size</span>: <span class="number">62.5%</span>;<span class="comment">/* 这样子使得font-size为16px * 62.5% = 10px */</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">html</span> <span class="selector-tag">body</span> <span class="selector-id">#root</span> <span class="selector-class">.App</span> {</span><br><span class="line"> <span class="attribute">min-height</span>: <span class="number">100vh</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>安装emotion</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add @emotion/react @emotion/styled</span><br></pre></td></tr></table></figure><ul><li><p>安装编辑器插件</p><ul><li>webstorm: <code>Styled Components & Styled JSX</code>,不过最新版本的好像都自动安装了</li><li>vscode: <code>vscode-styled-components</code></li></ul></li><li><p>使用emotion</p></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// html自带标签的使用</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Container</span> = styled.<span class="property">div</span></span><br><span class="line"> <span class="string">`</span></span><br><span class="line"><span class="string"> display: flex;</span></span><br><span class="line"><span class="string"> flex-direction: column;</span></span><br><span class="line"><span class="string"> align-items: center;</span></span><br><span class="line"><span class="string"> min-height: 100vh;</span></span><br><span class="line"><span class="string"> `</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 组件的使用</span></span><br><span class="line"><span class="keyword">import</span> {<span class="title class_">Card</span>} <span class="keyword">from</span> <span class="string">"antd"</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">ShowCard</span> = <span class="title function_">styled</span>(<span class="title class_">Card</span>)</span><br><span class="line"> <span class="string">`</span></span><br><span class="line"><span class="string"> box-sizing: border-box;</span></span><br><span class="line"><span class="string"> width: 40rem;</span></span><br><span class="line"><span class="string"> min-height: 56rem;</span></span><br><span class="line"><span class="string"> padding: 3.2rem 4rem;</span></span><br><span class="line"><span class="string"> border-radius: 0.3rem;</span></span><br><span class="line"><span class="string"> box-shadow: 0 0 1rem rgba(0,0,0,.1);</span></span><br><span class="line"><span class="string"> `</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>注意,不管有没有css样式后面,必须要接一个模板字符串,否者会报错</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//不报错</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">HeaderLeft</span> = <span class="title function_">styled</span>(<span class="title class_">Row</span>)<span class="string">``</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//报错</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">HeaderLeft</span> = <span class="title function_">styled</span>(<span class="title class_">Row</span>);</span><br></pre></td></tr></table></figure><ul><li>设置多个背景(学到了,学到了,)<ul><li><code>background-image</code> 属性用于为一个元素设置一个或者多个背景图像。</li><li><code>background-position</code>属性为每一个背景图片设置初位置<ul><li>一个值为x,y设置相同的位置</li><li>二个值分别为x轴位置和y轴位置</li></ul></li><li><code>background-size</code>属性设置背景图片大小<ul><li>一个值: 指定图片的宽度,高度为<code>auto</code></li><li>二个值: 分别指定图片的高度 和 宽度</li><li>逗号分割多个值,设置多重背景</li></ul></li></ul></li></ul><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">/*设置背景图*/</span><br><span class="line">background-repeat: no-repeat;</span><br><span class="line">background-position: left bottom, right bottom;</span><br><span class="line">background-size: calc(((100vw - 40rem)/2) - 3.2rem ) ,calc(((100vw - 40rem)/2) - 3.2rem ),cover;</span><br><span class="line">background-attachment: fixed;</span><br><span class="line">background-image: url(${LeftBg}),url(${RightBg});</span><br></pre></td></tr></table></figure><h2 id="grid和flex各自的应用场景"><a href="#grid和flex各自的应用场景" class="headerlink" title="grid和flex各自的应用场景"></a>grid和flex各自的应用场景</h2><ul><li>一看空间<ul><li>一般来说,一维布局用flex,二维布局用grid</li></ul></li><li>二看内容和布局<ul><li>从内容出发: 有一组内容(数量一般不固定),然后希望他们均匀分布在容器在当中,并且由内容自己的大小决定占据的空间<strong>(用flex)</strong></li><li>从布局出发:先规划网格(数量一般比较固定),然后再把元素往里填充<strong>(用grid)</strong></li></ul></li></ul><h2 id="css-in-js-Row组件实现"><a href="#css-in-js-Row组件实现" class="headerlink" title="css-in-js:Row组件实现"></a>css-in-js:Row组件实现</h2><ul><li>emotion允许我们像react一样传递参数来达到自定义样式的效果<ul><li>Row组件样式</li><li>当然,可以不写ts在这里,不过不写会有警告在tsx当中~</li></ul></li></ul><figure class="highlight tsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> styled <span class="keyword">from</span> <span class="string">"@emotion/styled"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> styled.<span class="property">div</span><{</span><br><span class="line"> gap?: <span class="built_in">number</span> | <span class="built_in">boolean</span>,<span class="comment">//右侧间距设置</span></span><br><span class="line"> between?: <span class="built_in">boolean</span>,<span class="comment">//内容是否居中</span></span><br><span class="line"> marginBottom?:<span class="built_in">number</span>,<span class="comment">//距离底部距离</span></span><br><span class="line">}></span><br><span class="line"> <span class="string">`</span></span><br><span class="line"><span class="string"> display: flex;</span></span><br><span class="line"><span class="string"> align-items: center;</span></span><br><span class="line"><span class="string"> justify-content: <span class="subst">${ props => props.between ? <span class="string">'space-between'</span> : <span class="literal">undefined</span> }</span>;</span></span><br><span class="line"><span class="string"> margin-bottom: <span class="subst">${ props => props.marginBottom ? props.marginBottom : <span class="number">0</span> }</span>;</span></span><br><span class="line"><span class="string"> > * {</span></span><br><span class="line"><span class="string"> margin-top: 0!important;</span></span><br><span class="line"><span class="string"> margin-bottom: 0!important;</span></span><br><span class="line"><span class="string"> margin-right: <span class="subst">${ props => <span class="keyword">typeof</span> props.gap === <span class="string">'number'</span> ? props.gap + <span class="string">'rem'</span> : props.gap ? <span class="string">'2rem'</span> : <span class="literal">undefined</span>}</span></span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> `</span></span><br></pre></td></tr></table></figure><ul><li>使用</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> styled <span class="keyword">from</span> <span class="string">"@emotion/styled"</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Row</span> <span class="keyword">from</span> <span class="string">"../src/component/lib"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">HeaderLeft</span> = <span class="title function_">styled</span>(<span class="title class_">Row</span>)<span class="string">``</span>;</span><br><span class="line"><span class="comment">// 传入对应的参数即可</span></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">HeaderLeft</span> <span class="attr">gap</span> = <span class="string">{true}</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">h3</span>></span>Logo<span class="tag"></<span class="name">h3</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">h3</span>></span>Logo<span class="tag"></<span class="name">h3</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">h3</span>></span>Logo<span class="tag"></<span class="name">h3</span>></span></span></span><br><span class="line"><span class="language-xml"><span class="tag"></<span class="name">HeaderLeft</span>></span></span></span><br></pre></td></tr></table></figure><h2 id="完成项目列表页面样式"><a href="#完成项目列表页面样式" class="headerlink" title="完成项目列表页面样式"></a>完成项目列表页面样式</h2><ul><li><p><strong>使用emotion的css</strong></p><ul><li>在react当中,我们可以直接对组件使用<code>style</code>设置样式,但是不支持一些子元素选择符,伪类等一些高级选择器的</li></ul><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">MyComponent</span> <span class="attr">style</span>=<span class="string">{{</span> <span class="attr">marginBottom:</span>'<span class="attr">2rem</span>' }}/></span></span><br></pre></td></tr></table></figure><ul><li>所以我们可以使用<code>@emotion/react</code>来代替我们</li></ul><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** <span class="doctag">@jsx</span> jsx */</span></span><br><span class="line"><span class="keyword">import</span> { jsx } <span class="keyword">from</span> <span class="string">"@emotion/react"</span>;</span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">Form</span> <span class="attr">css</span>=<span class="string">{{marginBottom:</span> '<span class="attr">2rem</span>'}} ></span></span></span><br><span class="line"><span class="language-xml"> </span></span><br><span class="line"><span class="language-xml"></Form/></span></span><br></pre></td></tr></table></figure><ul><li>老师是这样子写的,但是我报错了<code>pragma and pragmaFrag cannot be set when runtime is automatic.</code>,不知道为什么,就这样子吧,后面遇到再说</li></ul></li><li><p><strong>图片以svg形式渲染</strong></p><ul><li>我们如果直接在React使用img去使用svg图片的时候,并不能去设置svg参数了</li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202302051551224.png"></p></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">Logo</span> <span class="keyword">from</span> <span class="string">"../src/assets/svg/software-logo.svg"</span>;</span><br><span class="line"><span class="comment">// 无法设置svg属性了</span></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">img</span> <span class="attr">src</span>=<span class="string">{Logo}/</span>></span></span></span><br></pre></td></tr></table></figure><ul><li><p>所以我们应该使用如下方式去使用svg图片(通过组件的形式),这样子我们就可以设置svg的一些参数了</p><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202302051551282.png"></p></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">ReactComponent</span> <span class="keyword">as</span> <span class="title class_">SoftwareLogo</span> } <span class="keyword">from</span> <span class="string">"../src/assets/svg/software-logo.svg"</span>;</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">SoftwareLogo</span> <span class="attr">width</span>=<span class="string">{</span>'<span class="attr">18rem</span>'} <span class="attr">color</span>=<span class="string">{</span>'<span class="attr">rgb</span>(<span class="attr">38</span>,<span class="attr">132</span>,<span class="attr">255</span>)'}/></span></span></span><br></pre></td></tr></table></figure><h2 id="清除警告todo"><a href="#清除警告todo" class="headerlink" title="清除警告todo"></a>清除警告todo</h2><ul><li><p><code>The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address a....</code></p><ul><li>原因:a标签没有href导致的,必须要一个合法的跳转链接,不可以<code>#</code>,也不可以<code>javascript:;</code></li><li>解决:替换为button,或者使用组件库,设置button的属性为<code>link</code></li></ul></li><li><p><code>React Hook useEffect has a missing dependency: 'callback'. Either include it or remove the dependency array.</code></p><ul><li>原因:依赖项没有加入在依懒收集里面导致报错</li><li>解决:</li></ul></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">useEffect</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="title function_">callback</span>();</span><br><span class="line"> <span class="comment">// todo 依懒项里加上callback会造成无限循环,这个和useCallback以及useMemo有关系</span></span><br><span class="line">},[])</span><br></pre></td></tr></table></figure><ul><li>不要乱用object<ul><li>覆盖范围很广,比如一个箭头函数变量,ts都认为这个是object</li></ul></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">isVoid</span> = (<span class="params">value:unknown</span>) => value === <span class="literal">undefined</span> || value == <span class="literal">null</span> || value === <span class="string">''</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*清除空对象*/</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">cleanEmptyObj</span> = (<span class="params">obj: {[key:string]:unknown}</span>) => {</span><br><span class="line"> <span class="keyword">const</span> temp = {...obj};</span><br><span class="line"> <span class="title class_">Object</span>.<span class="title function_">keys</span>(temp).<span class="title function_">forEach</span>(<span class="function"><span class="params">key</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> value = temp[key]</span><br><span class="line"> <span class="keyword">if</span>(<span class="title function_">isVoid</span>(value)){</span><br><span class="line"> <span class="keyword">delete</span> temp[key]</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">return</span> temp;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><p><code>Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.</code><strong>(我这边失败了,这个具体的就不加了)</strong></p><ul><li>原因:jira-dev-tool问题</li><li>解决:安装jira-dev-tool@next</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">yarn add jira-dev-tool@next</span><br><span class="line"></span><br><span class="line"><span class="title class_">App</span>.<span class="property">tsc</span></span><br><span class="line"></span><br><span class="line">- <span class="keyword">import</span> { loadDevTools } <span class="keyword">from</span> <span class="string">'jira-dev-tool'</span>;</span><br><span class="line">+ <span class="keyword">import</span> { loadServer,<span class="title class_">DevTools</span> } <span class="keyword">from</span> <span class="string">'jira-dev-tool'</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//原来写法</span></span><br><span class="line"><span class="title function_">loadDevTools</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="title class_">ReactDOM</span>.<span class="title function_">render</span>(</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">React.StrictMode</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">AppProvider</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">App</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">AppProvider</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">React.StrictMode</span>></span></span>,</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'root'</span>)</span><br><span class="line"> );</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//更改为</span></span><br><span class="line"><span class="title function_">loadServer</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="title class_">ReactDOM</span>.<span class="title function_">render</span>(</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">React.StrictMode</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">AppProvider</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">DevTools</span>/></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">App</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">AppProvider</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">React.StrictMode</span>></span></span>,</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'root'</span>)</span><br><span class="line"> );</span><br><span class="line">});</span><br></pre></td></tr></table></figure></li></ul><h2 id="登录注册页面loading和error状态处理"><a href="#登录注册页面loading和error状态处理" class="headerlink" title="登录注册页面loading和error状态处理"></a>登录注册页面loading和error状态处理</h2><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202302062204176.png"></p><h3 id="需要注意的是try-catch是同步的"><a href="#需要注意的是try-catch是同步的" class="headerlink" title="需要注意的是try-catch是同步的"></a>需要注意的是try-catch是同步的</h3><p>为什么不能用useAsync的error,因为error更新是异步的,try-catch是同步的</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">const</span> {run,isLoading,error} = <span class="title function_">useAsync</span>(<span class="literal">undefined</span>,{<span class="attr">throwOnError</span>: <span class="literal">true</span>});</span><br><span class="line"> <span class="comment">/*点击登录*/</span></span><br><span class="line"> <span class="keyword">const</span> <span class="title function_">handleSubmit</span> = <span class="keyword">async</span> (<span class="params">{username,password}: {username:string,password:string}</span>) => {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">await</span> <span class="title function_">run</span>(<span class="title function_">login</span>({ username, password }))</span><br><span class="line"> }<span class="keyword">catch</span> (e) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(e)</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line">当<span class="keyword">try</span> ... <span class="keyword">catch</span>执行完成后,才开始执行error的更新函数,所以你会发现,第一次error输出没有值,第二次error就有了(第二次的error为上一次出错的值)</span><br></pre></td></tr></table></figure><h3 id="未捕获错误-Uncaught-Errors-错误边界"><a href="#未捕获错误-Uncaught-Errors-错误边界" class="headerlink" title="未捕获错误(Uncaught Errors)-错误边界"></a>未捕获错误(Uncaught Errors)-错误边界</h3><ul><li><p>react官网对于错误边界的说明</p><ul><li><a target="_blank" rel="noopener" href="https://react.docschina.org/docs/error-boundaries.html">https://react.docschina.org/docs/error-boundaries.html</a></li></ul></li><li><p><strong>只有 class 组件才可以成为错误边界组件</strong></p></li><li><p>react-error-boundary</p><ul><li><a target="_blank" rel="noopener" href="https://github.com/bvaughn/react-error-boundaryx">https://github.com/bvaughn/react-error-boundaryx</a></li></ul></li><li><p>错误边界<strong>无法</strong>捕获以下场景中产生的错误:</p></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">事件处理</span><br><span class="line"></span><br><span class="line">异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)</span><br><span class="line"></span><br><span class="line">服务端渲染</span><br><span class="line"></span><br><span class="line">它自身抛出来的错误(并非它的子组件)</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><p>老师创建的组件的要求</p><ul><li>1.可以自定义错误显示的组件</li><li>2.可以展示子组件当没有错误的时候</li></ul></li><li><p>代码</p></li></ul><figure class="highlight tsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, {<span class="title class_">Component</span>, <span class="title class_">ErrorInfo</span>, <span class="title class_">ReactNode</span>} <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">type</span> <span class="title class_">Props</span> = {</span><br><span class="line"> <span class="attr">children</span>:<span class="title class_">ReactNode</span>,<span class="comment">//子组件</span></span><br><span class="line"> fallBackRender : <span class="function">(<span class="params">props: { error:<span class="built_in">Error</span> | <span class="literal">null</span> }</span>) =></span> <span class="title class_">React</span>.<span class="property">ReactElement</span>,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">interface</span> <span class="title class_">State</span> {</span><br><span class="line"> <span class="attr">error</span>: <span class="title class_">Error</span> | <span class="literal">null</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">Boundary</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Component</span><<span class="title class_">Props</span>, <span class="title class_">State</span>> {</span><br><span class="line"> state = {</span><br><span class="line"> <span class="attr">error</span>:<span class="literal">null</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="title function_">getDerivedStateFromError</span>(<span class="params">error:<span class="built_in">Error</span></span>){</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> error</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">componentDidCatch</span>(<span class="params">error:<span class="built_in">Error</span>, errorInfo:ErrorInfo</span>) {</span><br><span class="line"> <span class="comment">// 你同样可以将错误日志上报给服务器</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">const</span> { error } = <span class="variable language_">this</span>.<span class="property">state</span>;</span><br><span class="line"> <span class="keyword">const</span> { children, fallBackRender } = <span class="variable language_">this</span>.<span class="property">props</span>;</span><br><span class="line"> <span class="keyword">if</span>(error) <span class="keyword">return</span> <span class="title function_">fallBackRender</span>({error})</span><br><span class="line"> <span class="keyword">return</span> children;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="使用useRef实现useDocumentTitle"><a href="#使用useRef实现useDocumentTitle" class="headerlink" title="使用useRef实现useDocumentTitle"></a>使用useRef实现useDocumentTitle</h2><ul><li><p>需求</p><ul><li>每一个组件可以使用<code>useDocumentTitle</code>方法,第一个参数传入新标题,第二个标题传入卸载组件后是否复原</li></ul></li><li><p>疑问</p><ul><li>为什么useDocumentTitle当中的设置<code>document.title</code>要放置在<code>useEffect</code></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">因为在函数组件主体内(这里指在 React 渲染阶段)改变 DOM、添加订阅、设置定时器、记录日志以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性。</span><br><span class="line"></span><br><span class="line">使用 useEffect 完成副作用操作。赋值给 useEffect 的函数会在组件渲染到屏幕之后执行。你可以把 effect 看作从 React 的纯函数式世界通往命令式世界的逃生通道。</span><br><span class="line"></span><br><span class="line">说通俗点就是useEffect可以放置一些副作用操作在里面,并设置为依赖.而我们的document.title就是一个副作用,所以需要放置在useEffect</span><br><span class="line"></span><br><span class="line">别忘记了`effect`单词本身的意思哦</span><br></pre></td></tr></table></figure><ul><li>useRef为什么要使用</li></ul></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 网页标题更改 */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useDocumentTitle</span> = (<span class="params">title:string,keepOnUnmount:boolean = <span class="literal">true</span></span>) => {</span><br><span class="line"> <span class="comment">//获取旧标题</span></span><br><span class="line"> <span class="keyword">const</span> oldTitle = <span class="variable language_">document</span>.<span class="property">title</span>;</span><br><span class="line"> <span class="title function_">useEffect</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">title</span> = title;</span><br><span class="line"> },[title])</span><br><span class="line"> <span class="comment">//更改新标题(副作用,使用需要使用useEffect)</span></span><br><span class="line"> <span class="title function_">useEffect</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">if</span>(!keepOnUnmount) {</span><br><span class="line"> <span class="comment">//卸载的时候执行</span></span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">title</span> = oldTitle</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> },[]);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//在上述代码中,因为闭包的问题,导致`oldTitle`可以保存最老的值</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//但是控制台可能会有警告,所以我们加入依赖,但是这又导致了oldTitle永远都是最新的值(也就是每执行一次,当前组件的oldTime都会被更新为上一次的值,而不是我们所想的指向最初始的title)</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useDocumentTitle</span> = (<span class="params">title:string,keepOnUnmount:boolean = <span class="literal">true</span></span>) => {</span><br><span class="line"> <span class="comment">//获取旧标题</span></span><br><span class="line"> <span class="keyword">const</span> oldTitle = <span class="variable language_">document</span>.<span class="property">title</span>;</span><br><span class="line"> <span class="title function_">useEffect</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">title</span> = title;</span><br><span class="line"> },[title])</span><br><span class="line"> <span class="comment">//更改新标题(副作用,使用需要使用useEffect)</span></span><br><span class="line"> <span class="title function_">useEffect</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">if</span>(!keepOnUnmount) {</span><br><span class="line"> <span class="comment">//卸载的时候执行</span></span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">title</span> = oldTitle</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> },[keepOnUnmount,oldTitle]);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">所以我们可以借助useRef</span><br><span class="line">useRef 返回一个可变的 ref 对象,其 .<span class="property">current</span> 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。</span><br><span class="line"><span class="comment">//代码改造如下</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useDocumentTitle</span> = (<span class="params">title:string,keepOnUnmount:boolean = <span class="literal">true</span></span>) => {</span><br><span class="line"> <span class="comment">//获取旧标题</span></span><br><span class="line"> <span class="keyword">const</span> oldTitle = <span class="title function_">useRef</span>(<span class="variable language_">document</span>.<span class="property">title</span>).<span class="property">current</span>;</span><br><span class="line"> <span class="comment">//更改新标题(副作用,使用需要使用useEffect)</span></span><br><span class="line"> <span class="title function_">useEffect</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">title</span> = title;</span><br><span class="line"> <span class="keyword">return</span> <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">if</span>(!keepOnUnmount) {</span><br><span class="line"> <span class="comment">//卸载的时候执行</span></span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">title</span> = oldTitle</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> },[title,keepOnUnmount,oldTitle]);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="动态改变网页标签显示的标题-todo"><a href="#动态改变网页标签显示的标题-todo" class="headerlink" title="动态改变网页标签显示的标题#todo"></a>动态改变网页标签显示的标题#todo</h2><ul><li>第一种<ul><li>react-helmet</li></ul></li><li>第二种</li></ul><h2 id="添加项目列表和项目详情"><a href="#添加项目列表和项目详情" class="headerlink" title="添加项目列表和项目详情"></a>添加项目列表和项目详情</h2><ul><li><p>react-router-dom和react-router的关系</p><ul><li>react-router管理路由关系,计算结果由react-router-dom来消费使用</li></ul></li><li><p>为什么Link是从react-router-dom引入的</p><ul><li>因为Link会被渲染为一个a标签,并且需要处理点击事件,和浏览器是相关联的</li></ul></li><li><p>路由表和路由的书写<strong>技巧</strong></p><ul><li><strong>不可以写斜杆</strong>,写斜杆代表不管你从哪里开始,我都是从<code>/</code>开始的,<br>所以我们需要在不破坏当前路由的基础上把路由加进去,所以不能有<code>/</code></li><li><code>/</code>带了斜杆就是根了(也就url的路径从我开始算起)</li><li><code>./</code>在不破坏当前路径下载后面添加内容,也可以不写<code>./</code></li><li>于是乎下面三个效果都是一样的,最终匹配的都是/home/message</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//路由表</span></span><br><span class="line">{</span><br><span class="line"> <span class="attr">path</span>:<span class="string">'/home'</span>,</span><br><span class="line"> <span class="attr">element</span>:<span class="language-xml"><span class="tag"><<span class="name">Home</span>/></span></span></span><br><span class="line"> <span class="attr">children</span>:[</span><br><span class="line"> <span class="attr">path</span>:<span class="string">"./message"</span>,</span><br><span class="line"> <span class="attr">path</span>:<span class="string">'/home/message'</span>,</span><br><span class="line"> <span class="attr">path</span>:<span class="string">'message'</span>,</span><br><span class="line"> ]</span><br><span class="line">}</span><br><span class="line"><span class="comment">//路由链接的to的书写也和这个相同,</span></span><br><span class="line"><span class="comment">//下面二个均是在对应url后面添加相应的内容</span></span><br><span class="line"><span class="comment">//比如之前url为/home,那么点击`message组件显示`,</span></span><br><span class="line"><span class="comment">//那么url就会变为/home/message</span></span><br><span class="line"><<span class="title class_">NavLink</span> to=<span class="string">"message"</span>><span class="title class_">Message</span>组件显示</<span class="title class_">NavLink</span>></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">NavLink</span> <span class="attr">to</span>=<span class="string">"news"</span>></span>News组件显示<span class="tag"></<span class="name">NavLink</span>></span></span></span><br></pre></td></tr></table></figure></li><li><p><strong>一个很奇怪的问题</strong></p><ul><li><strong>必须要转化为字符串才可以</strong></li></ul></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">return <Link to={String(project.id)}>{ project.name } </Link></span><br></pre></td></tr></table></figure><ul><li><strong>注意Navigate写法</strong></li></ul><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><h1><span class="title class_">ProjectScreen</span></h1></span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">Link</span> <span class="attr">to</span>=<span class="string">{</span>'<span class="attr">kanban</span>'}></span>看板<span class="tag"></<span class="name">Link</span>></span></span></span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">Link</span> <span class="attr">to</span>=<span class="string">{</span>'<span class="attr">epic</span>'}></span>任务组<span class="tag"></<span class="name">Link</span>></span></span></span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">Routes</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">Route</span> <span class="attr">path</span>=<span class="string">{</span>'<span class="attr">kanban</span>'} <span class="attr">element</span>=<span class="string">{</span><<span class="attr">KanbanScreen</span>/></span>}><span class="tag"></<span class="name">Route</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">Route</span> <span class="attr">path</span>=<span class="string">{</span>'<span class="attr">epic</span>'} <span class="attr">element</span>=<span class="string">{</span><<span class="attr">EpicScreen</span>/></span>}><span class="tag"></<span class="name">Route</span>></span></span></span><br><span class="line"><span class="language-xml"> {/*/!*<span class="tag"><<span class="name">Navigate</span> <span class="attr">to</span>=<span class="string">{window.location.pathname</span> + '/<span class="attr">kanban</span>'}/></span>*!/ react5写法*/}</span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">Route</span> <span class="attr">path</span>=<span class="string">{</span>''} <span class="attr">element</span>=<span class="string">{</span><<span class="attr">Navigate</span> <span class="attr">to</span>=<span class="string">{</span>'<span class="attr">kanban</span>'}/></span>}/></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">Routes</span>></span></span></span><br><span class="line"> </div></span><br></pre></td></tr></table></figure><h2 id="useSearchParams初步完成"><a href="#useSearchParams初步完成" class="headerlink" title="useSearchParams初步完成"></a>useSearchParams初步完成</h2><ul><li>可以用来获取search参数(也就是url后面的这种参数<code>/a?id=4&age=14</code>)</li><li>返回一个<a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchParams">URLSearchParams</a>,</li><li>所以要读取某一个值就需要使用<code>get</code>方法</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//url</span></span><br><span class="line"> /a?id=<span class="number">4</span>&age=<span class="number">14</span></span><br><span class="line"><span class="keyword">const</span> [a] = <span class="title function_">useSearchParams</span>();</span><br><span class="line">a.<span class="title function_">get</span>(age);<span class="comment">//输出14</span></span><br></pre></td></tr></table></figure><ul><li><p>问题</p><ul><li>为什么没有<code>as const</code>会出现下图问题</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {useSearchParams} <span class="keyword">from</span> <span class="string">"react-router-dom"</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useUrlQueryParams</span> = (<span class="params">keys:<span class="built_in">string</span>[]</span>) => {</span><br><span class="line"> <span class="keyword">const</span> [searchParams] = <span class="title function_">useSearchParams</span>();</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> keys.<span class="title function_">reduce</span>(<span class="function">(<span class="params">pre,key</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> {...pre,[key]:searchParams.<span class="title function_">get</span>(key) ?? <span class="string">''</span>}</span><br><span class="line"> },{} ),</span><br><span class="line"> searchParams,</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202302142120245.png" alt="查看返回值类型"></p><ul><li>先来看一个小例子<ul><li><strong>想一想a的类型是什么</strong></li></ul></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> a = [<span class="string">'jack'</span>,<span class="number">12</span>,{<span class="attr">gender</span>:<span class="string">'男'</span>}]</span><br></pre></td></tr></table></figure><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202302142111118.png" alt="a的类型"></p><ul><li>原因很简单,因为ts认为数组都是相同的,使用为了确保数组当中都有相同的,所以就使用了多个<code>|</code></li><li>所以我们return后面添加一个<code>as const</code>即可</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useUrlQueryParams</span> = (<span class="params">keys:<span class="built_in">string</span>[]</span>) => {</span><br><span class="line"> <span class="keyword">const</span> [searchParams] = <span class="title function_">useSearchParams</span>();</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> keys.<span class="title function_">reduce</span>(<span class="function">(<span class="params">pre,key</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> {...pre,[key]:searchParams.<span class="title function_">get</span>(key) ?? <span class="string">''</span>}</span><br><span class="line"> },{} ),</span><br><span class="line"> searchParams,</span><br><span class="line"> ] <span class="keyword">as</span> <span class="keyword">const</span> </span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202302142121728.png"></p></li><li><p>不过这还不够,我们点入reduce的ts声明可以看到,reduce当中<code>previousValue</code>返回值依赖于初始化时候传入的泛型,所以我们可以指明initialValue在reduce当中</p></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">reduce</span>(<span class="attr">callbackfn</span>: <span class="function">(<span class="params">previousValue: T, currentValue: T, currentIndex: <span class="built_in">number</span>, array: T[]</span>) =></span> T, <span class="attr">initialValue</span>: T): T;</span><br></pre></td></tr></table></figure><ul><li>最终初步完成如下</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useUrlQueryParams</span> = (<span class="params">keys:<span class="built_in">string</span>[]</span>) => {</span><br><span class="line"> <span class="keyword">const</span> [searchParams,setSearchParams] = <span class="title function_">useSearchParams</span>();</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> keys.<span class="title function_">reduce</span>(<span class="function">(<span class="params">pre,key</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> {...pre,[key]:searchParams.<span class="title function_">get</span>(key) ?? <span class="string">''</span>}</span><br><span class="line"> },{} <span class="keyword">as</span> {[key <span class="keyword">in</span> <span class="built_in">string</span>]:<span class="built_in">string</span>}),</span><br><span class="line"> setSearchParams,</span><br><span class="line"> ] <span class="keyword">as</span> <span class="keyword">const</span> </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="useSearchParams完成-使用useMemo解决"><a href="#useSearchParams完成-使用useMemo解决" class="headerlink" title="useSearchParams完成(使用useMemo解决)"></a>useSearchParams完成(使用useMemo解决)</h2><ul><li><p>上一次完成的方法我们使用发现会无限渲染我们可以借助<code>why-did-you-render</code>来检测是什么造成了页面渲染</p></li><li><p>通过排查,<strong>useDebounce当中的useEffect发现依赖项目变化了,进而去重新渲染页面,但是params在每次渲染的时候都是一个新的,导致useEffect又认为发生了变化,进而重复无限渲染</strong></p><ul><li>所以我们使用<code>useEffect</code>的时候,<strong>我们应该将基本类型和组件状态(使用useState)放置到依赖里面,非组件状态的对象,绝对不可以放在依赖里面!!</strong></li><li>所以检查我们可以使用<a target="_blank" rel="noopener" href="https://www.npmjs.com/package/@welldone-software/why-did-you-render">why-did-you-render</a></li></ul></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> [params] = <span class="title function_">useUrlQueryParams</span>([<span class="string">'name'</span>,<span class="string">'age'</span>])</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> debounceValue = <span class="title function_">useDebounce</span>(params,<span class="number">100</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*自定义防抖hooks*/</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> useDebounce = <T>(<span class="attr">value</span>:T,delay?:<span class="built_in">number</span>):<span class="function"><span class="params">T</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> [debounceValue,setDebounceValue] = <span class="title function_">useState</span>(value)</span><br><span class="line"> <span class="title function_">useEffect</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">const</span> timer = <span class="built_in">setTimeout</span>(<span class="function">() =></span> { <span class="title function_">setDebounceValue</span>(value) },delay);</span><br><span class="line"> <span class="keyword">return</span> <span class="function">() =></span> {</span><br><span class="line"> <span class="comment">/*下一次effect执行前的处理*/</span></span><br><span class="line"> <span class="built_in">clearTimeout</span>(timer)</span><br><span class="line"> }</span><br><span class="line"> },[value,delay])</span><br><span class="line"> <span class="keyword">return</span> debounceValue;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>所以我们循环遍历search参数的时候,返回的是一个对象,又因为react只对对象进行地址比较,所以就导致每次重新渲染返回的对象不同,所以就造成了重复渲染,解决后代码如下(使用<code>useMemo</code>)</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> useUrlQueryParams = <K <span class="keyword">extends</span> <span class="built_in">string</span>><span class="function">(<span class="params">keys:K[]</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> [searchParams,setSearchParams] = <span class="title function_">useSearchParams</span>();</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> <span class="title function_">useMemo</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> keys.<span class="title function_">reduce</span>(<span class="function">(<span class="params">pre,key</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> {...pre,[key]:searchParams.<span class="title function_">get</span>(key) ?? <span class="string">''</span>}</span><br><span class="line"> },{} <span class="keyword">as</span> {[key <span class="keyword">in</span> K]:<span class="built_in">string</span>})</span><br><span class="line"> },[searchParams]),</span><br><span class="line"> setSearchParams,</span><br><span class="line"> ] <span class="keyword">as</span> <span class="keyword">const</span></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="完成的URL状态管理代码"><a href="#完成的URL状态管理代码" class="headerlink" title="完成的URL状态管理代码"></a>完成的URL状态管理代码</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> useUrlQueryParams = <K <span class="keyword">extends</span> string><span class="function">(<span class="params">keys:K[]</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> [searchParams,setSearchParams] = <span class="title function_">useSearchParams</span>();</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> <span class="title function_">useMemo</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> keys.<span class="title function_">reduce</span>(<span class="function">(<span class="params">pre,key</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> {...pre,[key]:searchParams.<span class="title function_">get</span>(key) ?? <span class="string">''</span>}</span><br><span class="line"> },{} <span class="keyword">as</span> {[key <span class="keyword">in</span> K]:string})</span><br><span class="line"> },[searchParams]),</span><br><span class="line"> <span class="function">(<span class="params">params:Partial<{[key <span class="keyword">in</span> K] : unknown}></span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> o = <span class="title function_">cleanEmptyObj</span>({...<span class="title class_">Object</span>.<span class="title function_">fromEntries</span>(searchParams),...params}) <span class="keyword">as</span> <span class="title class_">URLSearchParamsInit</span></span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">setSearchParams</span>(o);</span><br><span class="line"> }</span><br><span class="line"> ] <span class="keyword">as</span> <span class="keyword">const</span></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="实现Id-Select解决Id难题"><a href="#实现Id-Select解决Id难题" class="headerlink" title="实现Id-Select解决Id难题"></a>实现Id-Select解决Id难题</h2><ul><li><p>获取AntDesign组件当中属性的二种方式</p><ul><li>方法1:通过<code>React.ComponentProps</code>;</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"><span class="keyword">import</span> {<span class="title class_">Select</span>} <span class="keyword">from</span> <span class="string">"antd"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">SelectProps</span> = <span class="title class_">React</span>.<span class="property">ComponentProps</span><<span class="keyword">typeof</span> <span class="title class_">Select</span>>;</span><br></pre></td></tr></table></figure><ul><li>方法2:Ctrl按照进入组件,然后找到后复制粘贴就可以引入</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {<span class="title class_">SelectProps</span>} <span class="keyword">from</span> <span class="string">"antd/es/select"</span>;</span><br></pre></td></tr></table></figure></li></ul><h2 id="用useEditProject编辑项目"><a href="#用useEditProject编辑项目" class="headerlink" title="用useEditProject编辑项目"></a>用useEditProject编辑项目</h2><h3 id="柯里化"><a href="#柯里化" class="headerlink" title="柯里化"></a>柯里化</h3><ul><li><strong>因为有一个参数实现已经知道了,后一个参数需要等待才可以知道,就可以采用这种方式</strong></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> { mutate } = <span class="title function_">useEditProject</span>();</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">pinProject</span> = (<span class="params">id:<span class="built_in">number</span></span>) => <span class="function">(<span class="params">checked:<span class="built_in">boolean</span></span>) =></span> <span class="title function_">mutate</span>({id,<span class="attr">pin</span>:checked})</span><br><span class="line"><<span class="title class_">Pin</span> checked={project.<span class="property">pin</span>} onCheckedChange={<span class="title function_">pinProject</span>(project.<span class="property">id</span>)}/></span><br><span class="line"></span><br><span class="line">等同于</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">pinProject</span> = (<span class="params">id:<span class="built_in">number</span>,checked:<span class="built_in">boolean</span></span>) => {</span><br><span class="line"> <span class="title function_">mutate</span>({id,<span class="attr">pin</span>:checked})</span><br><span class="line">} </span><br><span class="line"><<span class="title class_">Pin</span> checked={project.<span class="property">pin</span>} onCheckedChange={<span class="function">(<span class="params">checked:<span class="built_in">boolean</span></span>) =></span> <span class="title function_">pinProject</span>(project.<span class="property">id</span>,checked) }/></span><br></pre></td></tr></table></figure><h3 id="惰性初始化和使用useRef保存函数和useState保存函数的方法"><a href="#惰性初始化和使用useRef保存函数和useState保存函数的方法" class="headerlink" title="惰性初始化和使用useRef保存函数和useState保存函数的方法"></a>惰性初始化和使用useRef保存函数和useState保存函数的方法</h3><h4 id="什么是惰性初始化"><a href="#什么是惰性初始化" class="headerlink" title="什么是惰性初始化"></a>什么是惰性初始化</h4><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202302212136514.png"></p><ul><li>惰性初始化的时候(也就是传入一个函数就是惰性初始),此函数会被立即执行,并将返回的值作为返回数组的第一个参数,其他和普通state是相同的(调用setState也会触发页面重新渲染)</li><li>惰性初始代码<ul><li>示例:<a target="_blank" rel="noopener" href="https://stackblitz.com/edit/react-ts-2meygh?file=App.tsx">https://stackblitz.com/edit/react-ts-2meygh?file=App.tsx</a></li></ul></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> [state,setState] = <span class="title function_">useState</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">const</span> initialState = <span class="title function_">someExpensiveComputation</span>(props);</span><br><span class="line"> <span class="keyword">return</span> initialState;</span><br><span class="line">})</span><br></pre></td></tr></table></figure><ul><li>非惰性初始(也就是普通的state,传入的不是一个函数,)</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> [state,setState] = <span class="title function_">useState</span>(<span class="title function_">someExpensiveComputation</span>(props));</span><br><span class="line"><span class="keyword">const</span> [state,setState] = <span class="title function_">useState</span>({</span><br><span class="line"> <span class="attr">name</span>:<span class="string">'李白'</span>,</span><br><span class="line"> <span class="attr">sex</span>:<span class="string">'男'</span></span><br><span class="line">})</span><br></pre></td></tr></table></figure><ul><li>所以当我们想通过useState保存函数的时候,就不可以了,我们可以使用<code>useRef</code>来保存函数</li></ul><h4 id="useRef"><a href="#useRef" class="headerlink" title="useRef"></a>useRef</h4><ul><li>我觉得我快忘记了,再看看React官网的描述吧<ul><li>比较重点就是<strong>ref对象发生变化,并不会引发组件的重新渲染</strong>,useRef的值是保存在一个<code>.current</code>属性当中</li></ul></li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202302212156842.png"></p><ul><li>老师在最后说的一个问题,将代码改为下面样子,我们点击<code>设置callBack</code>后,再点击<code>执行callBack-设置后不正常输出'init'</code>按钮,发现输出的却是<code>init</code><ul><li>这是因为组件在编译渲染完成后,<code>执行callBack-设置后不正常输出'init'</code>按钮始终指向初次时候的函数地址,又因为useRef即使被更新也不会被重新渲染,导致此按钮指向的依旧是初始化时候的函数</li><li>而为什么<code>执行callBack-设置后正常输出'updated'</code>按钮却是正常输出,因为传入的是高阶函数,在执行的时候才会寻找<code>current</code>所指向的函数去执行,所以执行就没有问题</li></ul></li></ul><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> <span class="title class_">React</span> <span class="keyword">from</span> <span class="string">'react'</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">'./style.css'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">App</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">const</span> callBackRef = <span class="title class_">React</span>.<span class="title function_">useRef</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">alert</span>(<span class="string">'init'</span>);</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">const</span> callBackCurrent = callBackRef.<span class="property">current</span>;</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'输出查看callBack的current(是否重新渲染)'</span>, callBackCurrent);</span><br><span class="line"> <span class="comment">// 设置callBack</span></span><br><span class="line"> <span class="keyword">const</span> <span class="title function_">setCallBack</span> = (<span class="params"></span>) => {</span><br><span class="line"> callBackRef.<span class="property">current</span> = <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">alert</span>(<span class="string">'updated'</span>);</span><br><span class="line"> };</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="comment">//执行callBack - 正常</span></span><br><span class="line"> <span class="keyword">const</span> <span class="title function_">fnCallBack</span> = (<span class="params"></span>) => {</span><br><span class="line"> callBackRef.<span class="title function_">current</span>();</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{setCallBack}</span>></span>设置callBack<span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{fnCallBack}</span>></span>执行callBack-设置后正常输出'updated'<span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{callBackRef.current}</span>></span></span></span><br><span class="line"><span class="language-xml"> 执行callBack-设置后不正常输出'init'</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">h1</span>></span>Hello StackBlitz!<span class="tag"></<span class="name">h1</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">p</span>></span>Start editing to see some magic happen :)<span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="useState保存函数的方法"><a href="#useState保存函数的方法" class="headerlink" title="useState保存函数的方法"></a>useState保存函数的方法</h4><ul><li>既然存在惰性初始化,我们就让他执行就可以,我们返回一个函数就可以啦</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> [retry,setRetry] = <span class="title function_">useState</span>(<span class="function">() =></span> <span class="function">() =></span> {</span><br><span class="line"> <span class="comment">//返回一个函数</span></span><br><span class="line">})</span><br></pre></td></tr></table></figure><h2 id="优化异步请求"><a href="#优化异步请求" class="headerlink" title="优化异步请求"></a>优化异步请求</h2><ul><li><p>出现的情况</p><ul><li>在外面等待数据返回的时候,突然退出登录,然后未中断请求,导致<code>setData</code>等操作会出现异常(我练习的时候好像没有,不过也学习下)</li></ul></li><li><p>解决异步的时候退出的问题</p></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1.建立useMountedRef,并设置状态</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* 返回组件的状态,如果没有挂载或者已经卸载,则返回false,</span></span><br><span class="line"><span class="comment">* */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">useMountedRef</span> = (<span class="params"></span>) => {</span><br><span class="line"> <span class="keyword">const</span> mountedRef = <span class="title function_">useRef</span>(<span class="literal">false</span>);</span><br><span class="line"> <span class="title function_">useEffect</span>(<span class="function">() =></span> {</span><br><span class="line"> mountedRef.<span class="property">current</span> = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="function">() =></span> {</span><br><span class="line"> mountedRef.<span class="property">current</span> = <span class="literal">false</span>;<span class="comment">//组件卸载</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">return</span> mountedRef</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 伪代码,当调用then的时候判断是否组件卸载了</span></span><br><span class="line"><span class="keyword">return</span> promiseGive</span><br><span class="line"> .<span class="title function_">then</span>(<span class="function">(<span class="params">res:D</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span>(mountedRef.<span class="property">current</span>){</span><br><span class="line"> <span class="title function_">setData</span>(res);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">resolve</span>(res);<span class="comment">//实现链式调用</span></span><br><span class="line">})</span><br><span class="line">.<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =></span> {</span><br><span class="line"> <span class="title function_">setError</span>(error);</span><br><span class="line"> <span class="keyword">if</span>(config.<span class="property">throwOnError</span>) <span class="keyword">return</span> <span class="title class_">Promise</span>.<span class="title function_">reject</span>(error);</span><br><span class="line"> <span class="keyword">return</span> error;<span class="comment">//实现链式调用</span></span><br><span class="line">})</span><br></pre></td></tr></table></figure><ul><li>当使用<code>useCallback</code>,或者<code>useMemo</code>的时候,可以里面会有依赖state,然后我们会将依赖加入进去,但是加入后,会发生无限循环的问题,这个时候我们就可以使用<code>setData</code>的第二种形式了,然后结合<code>useCallback</code>或者<code>useMemo</code></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//第一种(造成无限循环)</span></span><br><span class="line"> <span class="comment">//当data改变,触发重新渲染,因为当调用setData的时候,就代表data改变</span></span><br><span class="line"> <span class="comment">//然后触发useCallback的重新渲染,然后又调用setData,又代表data改变</span></span><br><span class="line"> <span class="comment">//又重新触发setData,,,,,,这样子无限循环下去</span></span><br><span class="line"><span class="keyword">const</span> handleChange = <span class="title function_">useCallback</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">const</span> [data,setData] = <span class="title function_">useState</span>({<span class="attr">name</span>:<span class="string">'李白'</span>,<span class="attr">loading</span>:<span class="literal">false</span>})</span><br><span class="line"> <span class="title function_">setData</span>({...state,<span class="attr">loading</span>:<span class="literal">true</span>})</span><br><span class="line">},[data,setData])</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//第二种(解决无限循环)</span></span><br><span class="line"><span class="keyword">const</span> handleChange = <span class="title function_">useCallback</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">const</span> [data,setData] = <span class="title function_">useState</span>({<span class="attr">name</span>:<span class="string">'李白'</span>,<span class="attr">loading</span>:<span class="literal">false</span>})</span><br><span class="line"> <span class="title function_">setData</span>(<span class="function">(<span class="params">preState</span>) =></span> {...preState,<span class="attr">loading</span>:<span class="literal">true</span>})</span><br><span class="line">},[setData])</span><br></pre></td></tr></table></figure><h4 id="什么时候使用useMemo-useCallback"><a href="#什么时候使用useMemo-useCallback" class="headerlink" title="什么时候使用useMemo,useCallback"></a>什么时候使用useMemo,useCallback</h4><ul><li>非基本类型想做依赖,就需要使用这二个</li><li><strong>比如在想自定义hooks的时候,返回了函数,或者非基本数据类型,或者并没有被useState包裹的数据的时候,就需要使用这二个了</strong></li></ul><h2 id="状态提升"><a href="#状态提升" class="headerlink" title="状态提升"></a>状态提升</h2><ul><li>const其实变量提升(依照var的变量提升,我们可以想一想组件的状态提升)</li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202302282118525.png"></p><ul><li><p>目前我们为了使用一个能被多个组件调用的方法或者是属性(可以称其为”<strong>全局方法或属性</strong>“),我们将其提升到共同的父组件当中,但是当子组件需要使用<strong>全局方法或属性</strong>的时候,父组件和要使用的子组件只有一层还好说,当有多层的时候,就会出现父传给A组件,A组件传递给B组件,B组件在传给C组件,C组件再来使用,来看看下面集中方法</p><ul><li><p><strong>第一种:</strong> 放在全局状态,通过一层一层传递,</p></li><li><p><strong>第二种:</strong> 还有一种Context的方法</p><ul><li><p><a target="_blank" rel="noopener" href="https://react.docschina.org/docs/context.html#when-to-use-context">@react官网说明</a></p></li><li><p>不适用content传递</p></li></ul><figure class="highlight tsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">Toolbar</span> <span class="attr">theme</span>=<span class="string">"dark"</span> /></span></span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Toolbar</span>(<span class="params">props</span>) {</span><br><span class="line"> <span class="comment">// Toolbar 组件接受一个额外的“theme”属性,然后传递给 ThemedButton 组件。</span></span><br><span class="line"> <span class="comment">// 如果应用中每一个单独的按钮都需要知道 theme 的值,这会是件很麻烦的事,</span></span><br><span class="line"> <span class="comment">// 因为必须将这个值层层传递所有组件。</span></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">ThemedButton</span> <span class="attr">theme</span>=<span class="string">{props.theme}</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ThemedButton</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">Button</span> <span class="attr">theme</span>=<span class="string">{this.props.theme}</span> /></span></span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>使用<code>createContext</code>传递</li></ul><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。</span></span><br><span class="line"><span class="comment">// 为当前的 theme 创建一个 context(“light”为默认值)。</span></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">ThemeContext</span> = <span class="title class_">React</span>.<span class="title function_">createContext</span>(<span class="string">'light'</span>);</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">App</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// 使用一个 Provider 来将当前的 theme 传递给以下的组件树。</span></span><br><span class="line"> <span class="comment">// 无论多深,任何组件都能读取这个值。</span></span><br><span class="line"> <span class="comment">// 在这个例子中,我们将 “dark” 作为当前的值传递下去。</span></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">ThemeContext.Provider</span> <span class="attr">value</span>=<span class="string">"dark"</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">Toolbar</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">ThemeContext.Provider</span>></span></span></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 中间的组件再也不必指明往下传递 theme 了。</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Toolbar</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">ThemedButton</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">ThemedButton</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span> {</span><br><span class="line"> <span class="comment">// 指定 contextType 读取当前的 theme context。</span></span><br><span class="line"> <span class="comment">// React 会往上找到最近的 theme Provider,然后使用它的值。</span></span><br><span class="line"> <span class="comment">// 在这个例子中,当前的 theme 值为 “dark”。</span></span><br><span class="line"> <span class="keyword">static</span> contextType = <span class="title class_">ThemeContext</span>;</span><br><span class="line"> <span class="title function_">render</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">Button</span> <span class="attr">theme</span>=<span class="string">{this.context}</span> /></span></span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p><strong>第三种:</strong> 组合组件(component composition)</p><ul><li>其实就是将组件传递(传递jsx) - 缺点是没有解决向下钻的问题,但是方法不需要传递了,(定义和调用很近),示例如下</li></ul><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用component composition</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Page</span>(<span class="params">props</span>) {</span><br><span class="line"> <span class="keyword">const</span> user = props.<span class="property">user</span>;</span><br><span class="line"> <span class="keyword">const</span> userLink = (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">Link</span> <span class="attr">href</span>=<span class="string">{user.permalink}</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">Avatar</span> <span class="attr">user</span>=<span class="string">{user}</span> <span class="attr">size</span>=<span class="string">{props.avatarSize}</span> /></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">Link</span>></span></span></span><br><span class="line"> );</span><br><span class="line"> <span class="keyword">return</span> <span class="language-xml"><span class="tag"><<span class="name">PageLayout</span> <span class="attr">userLink</span>=<span class="string">{userLink}</span> /></span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 现在,我们有这样的组件:</span></span><br><span class="line"><<span class="title class_">Page</span> user={user} avatarSize={avatarSize} /></span><br><span class="line"><span class="comment">// ... 渲染出 ...</span></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">PageLayout</span> <span class="attr">userLink</span>=<span class="string">{...}</span> /></span></span></span><br><span class="line"><span class="comment">// ... 渲染出 ...</span></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">NavigationBar</span> <span class="attr">userLink</span>=<span class="string">{...}</span> /></span></span></span><br><span class="line"><span class="comment">// ... 渲染出 ...</span></span><br><span class="line">{props.<span class="property">userLink</span>}</span><br><span class="line"></span><br><span class="line"><span class="comment">//未使用component composition之前</span></span><br><span class="line"><<span class="title class_">Page</span> user={user} avatarSize={avatarSize} /></span><br><span class="line"><span class="comment">// ... 渲染出 ...</span></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">PageLayout</span> <span class="attr">user</span>=<span class="string">{user}</span> <span class="attr">avatarSize</span>=<span class="string">{avatarSize}</span> /></span></span></span><br><span class="line"><span class="comment">// ... 渲染出 ...</span></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">NavigationBar</span> <span class="attr">user</span>=<span class="string">{user}</span> <span class="attr">avatarSize</span>=<span class="string">{avatarSize}</span> /></span></span></span><br><span class="line"><span class="comment">// ... 渲染出 ...</span></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">Link</span> <span class="attr">href</span>=<span class="string">{user.permalink}</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">Avatar</span> <span class="attr">user</span>=<span class="string">{user}</span> <span class="attr">size</span>=<span class="string">{avatarSize}</span> /></span></span></span><br><span class="line"><span class="language-xml"><span class="tag"></<span class="name">Link</span>></span></span></span><br></pre></td></tr></table></figure></li></ul></li></ul><h2 id="useUndo"><a href="#useUndo" class="headerlink" title="useUndo"></a>useUndo</h2><ul><li>未使用<code>useReducer</code>的写法</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {useCallback, useState} <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">UseUndo</span> = <T><span class="function">(<span class="params">initData:T</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> [state,setState] = useState<{</span><br><span class="line"> <span class="attr">backList</span>:T[],<span class="comment">//过去的记录</span></span><br><span class="line"> <span class="attr">present</span>:T,<span class="comment">//现在的值,</span></span><br><span class="line"> <span class="attr">goList</span>:T[],<span class="comment">//前面的记录</span></span><br><span class="line"> }>({</span><br><span class="line"> <span class="attr">backList</span>:[],</span><br><span class="line"> <span class="attr">goList</span>:[],</span><br><span class="line"> <span class="attr">present</span>:initData,</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">const</span> [canBack,setCanBack] = <span class="title function_">useState</span>(<span class="function">() =></span> state.<span class="property">backList</span>.<span class="property">length</span> > <span class="number">0</span>);<span class="comment">//是否可以后退</span></span><br><span class="line"> <span class="keyword">const</span> [canGo,setCanGo] = <span class="title function_">useState</span>(<span class="function">() =></span> state.<span class="property">goList</span>.<span class="property">length</span> > <span class="number">0</span>);<span class="comment">//是否可以前进</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 执行返回 */</span></span><br><span class="line"> <span class="keyword">const</span> execBack = <span class="title function_">useCallback</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="title function_">setState</span>(<span class="function">(<span class="params">currentState</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span>(!canBack) <span class="keyword">return</span> currentState;</span><br><span class="line"> <span class="keyword">const</span> { <span class="attr">goList</span>:oldGoList,<span class="attr">backList</span>:oldBackList } = currentState;</span><br><span class="line"> <span class="keyword">const</span> present = oldBackList[oldBackList.<span class="property">length</span>-<span class="number">1</span>];</span><br><span class="line"> <span class="keyword">const</span> backList = oldBackList.<span class="title function_">slice</span>(<span class="number">0</span>,oldGoList.<span class="property">length</span> - <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">const</span> goList = [...oldGoList,present];</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> goList,</span><br><span class="line"> backList,</span><br><span class="line"> present,</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> },[])</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 执行前进 */</span></span><br><span class="line"> <span class="keyword">const</span> execGo = <span class="title function_">useCallback</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="title function_">setState</span>(<span class="function">(<span class="params">currentState</span>) =></span> {</span><br><span class="line"> <span class="keyword">if</span>(!canGo) <span class="keyword">return</span> currentState;</span><br><span class="line"> <span class="keyword">const</span> { <span class="attr">goList</span>:oldGoList,<span class="attr">backList</span>:oldBackList } = currentState;</span><br><span class="line"> <span class="keyword">const</span> present = oldGoList[<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">const</span> goList = oldGoList.<span class="title function_">slice</span>(<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">const</span> backList = [...oldBackList,present];</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> goList,</span><br><span class="line"> backList,</span><br><span class="line"> present,</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> },[])</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 设置值 */</span></span><br><span class="line"> <span class="keyword">const</span> set = <span class="title function_">useCallback</span>(<span class="function">(<span class="params">newData:T</span>) =></span> {</span><br><span class="line"> <span class="title function_">setState</span>(<span class="function">(<span class="params">currentState</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> { <span class="attr">goList</span>:oldGoList,<span class="attr">backList</span>:oldBackList,<span class="attr">present</span>:oldPresent } = currentState;</span><br><span class="line"> <span class="keyword">if</span>(newData === oldPresent) <span class="keyword">return</span> currentState;</span><br><span class="line"> <span class="keyword">const</span> backList = [...oldBackList,oldPresent];</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">goList</span>:[],</span><br><span class="line"> backList,</span><br><span class="line"> <span class="attr">present</span>:newData,</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> },[])</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 重置 */</span></span><br><span class="line"> <span class="keyword">const</span> reset = <span class="title function_">useCallback</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="title function_">setState</span>(<span class="function">(<span class="params">currentState</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> { goList,backList } = currentState;</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">goList</span>:[],</span><br><span class="line"> <span class="attr">backList</span>:[],</span><br><span class="line"> <span class="attr">present</span>:initData,</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> },[])</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> state,</span><br><span class="line"> execBack,</span><br><span class="line"> execGo,</span><br><span class="line"> set,</span><br><span class="line"> reset,</span><br><span class="line"> canBack,</span><br><span class="line"> canGo,</span><br><span class="line"> ] <span class="keyword">as</span> <span class="keyword">const</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">UseUndo</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>使用<code>useReducer</code>的写法,仅供参考</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {useCallback, useReducer, useState} <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">enum</span> <span class="title class_">TypeOperation</span> {</span><br><span class="line"> go=<span class="string">'go'</span>,</span><br><span class="line"> back=<span class="string">'back'</span>,</span><br><span class="line"> set=<span class="string">'set'</span>,</span><br><span class="line"> reset=<span class="string">'reset'</span>,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">interface</span> <span class="title class_">State</span><T> {</span><br><span class="line"> <span class="attr">backList</span>:T[],<span class="comment">//过去的记录</span></span><br><span class="line"> <span class="attr">present</span>:T,<span class="comment">//现在的值,</span></span><br><span class="line"> <span class="attr">goList</span>:T[],<span class="comment">//前面的记录</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">interface</span> <span class="title class_">Action</span><T> {</span><br><span class="line"> newPresent?:T,</span><br><span class="line"> <span class="attr">type</span>: <span class="title class_">TypeOperation</span>,</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> unDoReducer = <T><span class="function">(<span class="params">state:State<T>,action:Action<T></span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> {<span class="keyword">type</span>,newPresent} = action;</span><br><span class="line"> <span class="keyword">const</span> { <span class="attr">goList</span>:oldGoList,<span class="attr">backList</span>:oldBackList,<span class="attr">present</span>:oldPresent } = state;</span><br><span class="line"> <span class="keyword">switch</span> (<span class="keyword">type</span>){</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"back"</span>: {</span><br><span class="line"> <span class="keyword">if</span>(oldBackList.<span class="property">length</span> ===<span class="number">0</span> ) <span class="keyword">return</span> state;</span><br><span class="line"> <span class="keyword">const</span> present = oldBackList[oldBackList.<span class="property">length</span>-<span class="number">1</span>];</span><br><span class="line"> <span class="keyword">const</span> backList = oldBackList.<span class="title function_">slice</span>(<span class="number">0</span>,oldGoList.<span class="property">length</span> - <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">const</span> goList = [...oldGoList,present];</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> goList,</span><br><span class="line"> backList,</span><br><span class="line"> present,</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"go"</span>: {</span><br><span class="line"> <span class="keyword">if</span>(oldGoList.<span class="property">length</span> === <span class="number">0</span>) <span class="keyword">return</span> state;</span><br><span class="line"> <span class="keyword">const</span> present = oldGoList[<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">const</span> goList = oldGoList.<span class="title function_">slice</span>(<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">const</span> backList = [...oldBackList,present];</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> goList,</span><br><span class="line"> backList,</span><br><span class="line"> present,</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"reset"</span>:{</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">goList</span>:[],</span><br><span class="line"> <span class="attr">backList</span>:[],</span><br><span class="line"> <span class="attr">present</span>:newPresent,</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"set"</span>: {</span><br><span class="line"> <span class="keyword">if</span>(newPresent === oldPresent) <span class="keyword">return</span> state;</span><br><span class="line"> <span class="keyword">const</span> backList = [...oldBackList,oldPresent];</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="attr">goList</span>:[],</span><br><span class="line"> backList,</span><br><span class="line"> <span class="attr">present</span>:newPresent,</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="attr">default</span>: <span class="keyword">return</span> state;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">UseUndo</span> = <T><span class="function">(<span class="params">initData:T</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> [state,dispatch] = <span class="title function_">useReducer</span>(unDoReducer,{</span><br><span class="line"> <span class="attr">backList</span>:[],</span><br><span class="line"> <span class="attr">goList</span>:[],</span><br><span class="line"> <span class="attr">present</span>:initData,</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">const</span> [canBack,setCanBack] = <span class="title function_">useState</span>(<span class="function">() =></span> state.<span class="property">backList</span>.<span class="property">length</span> > <span class="number">0</span>);<span class="comment">//是否可以后退</span></span><br><span class="line"> <span class="keyword">const</span> [canGo,setCanGo] = <span class="title function_">useState</span>(<span class="function">() =></span> state.<span class="property">goList</span>.<span class="property">length</span> > <span class="number">0</span>);<span class="comment">//是否可以前进</span></span><br><span class="line"> <span class="comment">/* 执行返回 */</span></span><br><span class="line"> <span class="keyword">const</span> execBack = <span class="title function_">useCallback</span>(<span class="function">() =></span> <span class="title function_">dispatch</span>({<span class="attr">type</span>:<span class="title class_">TypeOperation</span>.<span class="property">back</span>}),[dispatch])</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 执行前进 */</span></span><br><span class="line"> <span class="keyword">const</span> execGo = <span class="title function_">useCallback</span>(<span class="function">() =></span> <span class="title function_">dispatch</span>({<span class="attr">type</span>:<span class="title class_">TypeOperation</span>.<span class="property">go</span>}),[dispatch])</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 设置值 */</span></span><br><span class="line"> <span class="keyword">const</span> set = <span class="title function_">useCallback</span>(<span class="function">(<span class="params">newData:T</span>) =></span> <span class="title function_">dispatch</span>({<span class="attr">type</span>:<span class="title class_">TypeOperation</span>.<span class="property">set</span>,<span class="attr">newPresent</span>:newData}),[dispatch])</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 重置 */</span></span><br><span class="line"> <span class="keyword">const</span> reset = <span class="title function_">useCallback</span>(<span class="function">(<span class="params">newData:T</span>) =></span> <span class="title function_">dispatch</span>({<span class="attr">type</span>:<span class="title class_">TypeOperation</span>.<span class="property">reset</span>,<span class="attr">newPresent</span>:newData}),[dispatch])</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> state,</span><br><span class="line"> execBack,</span><br><span class="line"> execGo,</span><br><span class="line"> set,</span><br><span class="line"> reset,</span><br><span class="line"> canBack,</span><br><span class="line"> canGo,</span><br><span class="line"> ] <span class="keyword">as</span> <span class="keyword">const</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">UseUndo</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><strong>顺带一提</strong>,其实<code>useReudcer</code>里面的action,其实什么都可以,只是我们用的多的都是带有<code>type</code>的而已</li></ul><h2 id="redux"><a href="#redux" class="headerlink" title="redux"></a>redux</h2><ul><li><p>redux用在哪里都可以,react-redux连接redux.如果redux不使用在react,就可以不适用react-redux</p></li><li><p>redux作用就是用现在的<code>state</code>,产生下一个<code>state</code></p></li><li><p>当redux发生什么事情的时候,就会戳一下</p><ul><li>redux发生<code>dispatch</code>,触发<code>subscribe</code></li><li>dispatch -> counter -> store</li></ul></li><li><p>redux保持一个同步之前学习的,为什么呢?保持纯洁性,因为如果是异步请求了,就不是可预测了的</p><ul><li>副作用,对现实世界产生影响<ul><li>比如发送请求,修改全局变量</li></ul></li></ul></li><li><p>redux怎么知道要更新数据呢?怎么知道要执行<code>订阅</code>的内容呢?</p><ul><li>判断前一次的数据是否和后一次的数据相同,相同就不更新,不相同就不更新</li><li>这样子比较 变量 a === 变量b</li></ul></li><li><p>redux-thunk在redux里面处理异步流行的一个库(注意,redux可以进行异步操作,但是redux-thunk可以帮助我们隐藏异步实现的细节)</p></li><li><p>可以看到,组件内部并不想知道怎么请求的,(具体异步细节忽略)</p></li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202303051508887.png"></p><h2 id="reduxjs-tooltik和react-redux"><a href="#reduxjs-tooltik和react-redux" class="headerlink" title="reduxjs/tooltik和react-redux"></a>reduxjs/tooltik和react-redux</h2><ul><li>安装依赖</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add react-redux @reduxjs/tooltik</span><br></pre></td></tr></table></figure><h3 id="有关reduxjs-toolkit部分"><a href="#有关reduxjs-toolkit部分" class="headerlink" title="有关reduxjs/toolkit部分"></a>有关reduxjs/toolkit部分</h3><ul><li>书写片段<ul><li>project-list.slice.ts</li></ul></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {createSlice} <span class="keyword">from</span> <span class="string">"@reduxjs/toolkit"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> projectListSlice = <span class="title function_">createSlice</span>({</span><br><span class="line"> <span class="attr">name</span>:<span class="string">'projectListSlice'</span>,</span><br><span class="line"> <span class="attr">initialState</span>:{</span><br><span class="line"> <span class="attr">projectModalOpen</span>:<span class="literal">false</span>,</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">reducers</span>:{</span><br><span class="line"> <span class="comment">/* 开启对话框 */</span></span><br><span class="line"> <span class="title function_">openProjectModal</span>(<span class="params">state,action</span>){</span><br><span class="line"> <span class="comment">//immer帮我们处理了,所以我们可以直接在返回的state书写</span></span><br><span class="line"> state.<span class="property">projectModalOpen</span> = <span class="literal">true</span>;</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">/* 关闭对话框 */</span></span><br><span class="line"> <span class="title function_">closeProjectModal</span>(<span class="params">state,action</span>){</span><br><span class="line"> state.<span class="property">projectModalOpen</span> = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> projectListSliceReducer = projectListSlice.<span class="property">reducer</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>主入口<ul><li>index.tsx</li></ul></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {configureStore} <span class="keyword">from</span> <span class="string">"@reduxjs/toolkit"</span>;</span><br><span class="line"><span class="keyword">import</span> {projectListSliceReducer} <span class="keyword">from</span> <span class="string">"../pages/projectList/projectList.slice"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> store = <span class="title function_">configureStore</span>({</span><br><span class="line"> <span class="comment">/* 设置状态管理 */</span></span><br><span class="line"> <span class="attr">reducer</span>:{</span><br><span class="line"> <span class="attr">projectList</span>:projectListSliceReducer</span><br><span class="line"> },</span><br><span class="line">})</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="有关react-redux"><a href="#有关react-redux" class="headerlink" title="有关react-redux"></a>有关react-redux</h3><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {<span class="title class_">AuthProvider</span>} <span class="keyword">from</span> <span class="string">"./authContext"</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>, {<span class="title class_">ReactNode</span>} <span class="keyword">from</span> <span class="string">"react"</span></span><br><span class="line"><span class="keyword">import</span> {store} <span class="keyword">from</span> <span class="string">"../store"</span>;<span class="comment">//新增</span></span><br><span class="line"><span class="keyword">import</span> {<span class="title class_">Provider</span>} <span class="keyword">from</span> <span class="string">"react-redux"</span>;<span class="comment">//新增</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">AppProvider</span> = (<span class="params">{children}:{children:ReactNode}</span>) => {</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">Provider</span> <span class="attr">store</span>=<span class="string">{store}</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">AuthProvider</span>></span></span></span><br><span class="line"><span class="language-xml"> { children }</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">AuthProvider</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">Provider</span>></span></span></span><br><span class="line"> )</span><br><span class="line">}</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">AppProvider</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><ul><li>获取设置的state参数<code>const { useSelector } from "react-redux"</code></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {useSelector} <span class="keyword">from</span> <span class="string">"react-redux"</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">selectProjectModalOpen</span> = state => state.<span class="property">projectList</span>.<span class="property">projectModalOpen</span>;</span><br><span class="line"><span class="keyword">const</span> showModal = <span class="title function_">useSelector</span>(selectProjectModalOpen);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//等同于 const showModal = useSelector((state) => state.projectList.projectModalOpen)</span></span><br></pre></td></tr></table></figure><ul><li>调用设置的方法<code>const { useDispatch } from "react-redux"</code></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> { useDispatch } <span class="keyword">from</span> <span class="string">"react-redux"</span>;</span><br><span class="line"><span class="keyword">import</span> {projectListSliceActions} <span class="keyword">from</span> <span class="string">"../projectList/projectList.slice"</span>;</span><br><span class="line"><span class="keyword">const</span> dispatch = <span class="title function_">useDispatch</span>();<span class="comment">//不需要传入任何参数,react-redux会自动去处理store</span></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{()</span> =></span> dispatch(projectListSliceActions.closeProjectModal())}>点击我关闭<span class="tag"></<span class="name">button</span>></span></span></span><br></pre></td></tr></table></figure><ul><li>这里面的<code>projectListSliceActions</code>对应下面暴露出来的<code>projectListSliceActions</code></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {createSlice} <span class="keyword">from</span> <span class="string">"@reduxjs/toolkit"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> projectListSlice = <span class="title function_">createSlice</span>({</span><br><span class="line"> <span class="attr">name</span>:<span class="string">'projectListSlice'</span>,</span><br><span class="line"> <span class="attr">initialState</span>:{</span><br><span class="line"> <span class="attr">projectModalOpen</span>:<span class="literal">false</span>,</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">reducers</span>:{</span><br><span class="line"> <span class="comment">/* 开启对话框 */</span></span><br><span class="line"> <span class="title function_">openProjectModal</span>(<span class="params">state</span>){</span><br><span class="line"> <span class="comment">//immer帮我们处理了,所以我们可以直接在返回的state书写</span></span><br><span class="line"> state.<span class="property">projectModalOpen</span> = <span class="literal">true</span>;</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">/* 关闭对话框 */</span></span><br><span class="line"> <span class="title function_">closeProjectModal</span>(<span class="params">state</span>){</span><br><span class="line"> state.<span class="property">projectModalOpen</span> = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> projectListSliceReducer = projectListSlice.<span class="property">reducer</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> projectListSliceActions = projectListSlice.<span class="property">actions</span>;</span><br><span class="line"><span class="comment">//获取state,从store当中的reducer获取值</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">selectProjectModalOpen</span> = (<span class="params">state</span>) => state.<span class="property">projectList</span>.<span class="property">projectModalOpen</span>;</span><br></pre></td></tr></table></figure><h3 id="执行异步"><a href="#执行异步" class="headerlink" title="执行异步"></a>执行异步</h3><ul><li>具体可看这篇文章,这里做个记录~<ul><li><a target="_blank" rel="noopener" href="https://blog.csdn.net/m0_71485750/article/details/126764667">https://blog.csdn.net/m0_71485750/article/details/126764667</a></li></ul></li></ul><h4 id="方法1"><a href="#方法1" class="headerlink" title="方法1:"></a>方法1:</h4><ul><li><p>在home.js中, 通过createAsyncThunk函数创建一个异步的action</p><p>再在extraReducers中监听这个异步的action的状态, 当他处于fulfilled状态时, 获取到网络请求的数据, 并修改原来state中的数据</p></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { createSlice, createAsyncThunk } <span class="keyword">from</span> <span class="string">"@reduxjs/toolkit"</span></span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">"axios"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个异步的action</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> fetchHomeMultidataAction = <span class="title function_">createAsyncThunk</span>(<span class="string">"fetch/homemultidata"</span>, <span class="keyword">async</span> () => {</span><br><span class="line"> <span class="keyword">const</span> res = <span class="keyword">await</span> axios.<span class="title function_">get</span>(<span class="string">"http://123.207.32.32:8000/home/multidata"</span>)</span><br><span class="line"> <span class="comment">// 返回结果会传递到监听函数的actions中</span></span><br><span class="line"> <span class="keyword">return</span> res.<span class="property">data</span></span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> homeSlice = <span class="title function_">createSlice</span>({</span><br><span class="line"> <span class="attr">name</span>: <span class="string">"home"</span>,</span><br><span class="line"> <span class="attr">initialState</span>: {</span><br><span class="line"> <span class="attr">banners</span>: [],</span><br><span class="line"> <span class="attr">recommends</span>: []</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">// extraReducers中针对异步action, 监听它的状态</span></span><br><span class="line"> <span class="attr">extraReducers</span>: {</span><br><span class="line"> [fetchHomeMultidataAction.<span class="property">fulfilled</span>](state, { payload }) {</span><br><span class="line"> <span class="comment">// 在fulfilled状态下, 将state中的banners和recommends修改为网络请求后的数据</span></span><br><span class="line"> state.<span class="property">banners</span> = payload.<span class="property">data</span>.<span class="property">banner</span>.<span class="property">list</span></span><br><span class="line"> state.<span class="property">recommends</span> = payload.<span class="property">data</span>.<span class="property">recommend</span>.<span class="property">list</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> homeSlice.<span class="property">reducer</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>其他地方引入执行异步</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { useDispatch } <span class="keyword">from</span> <span class="string">"react-redux"</span>;</span><br><span class="line"><span class="keyword">const</span> dispatch = <span class="title function_">useDispatch</span>();</span><br><span class="line"><span class="title function_">dispatch</span>(<span class="title function_">fetchHomeMultidataAction</span>())</span><br></pre></td></tr></table></figure><h4 id="方法2"><a href="#方法2" class="headerlink" title="方法2"></a>方法2</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">如果我们不想通过在extraReducers在监听状态, 再修改state这种方法的话, 还有另外的一种做法</span><br><span class="line"></span><br><span class="line">我们创建的fetchHomeMultidataAction这个异步action是接受两个参数的</span><br><span class="line"></span><br><span class="line">参数一, extraInfo: 在派发这个异步action时, 如果有传递参数, 会放在extraInfo里面</span><br><span class="line">参数二, store: 第二个参数将store传递过来</span><br><span class="line">这样我们获取到结果后, 通过dispatch修改store中的state, 无需再监听异步action的状态</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { createSlice, createAsyncThunk } <span class="keyword">from</span> <span class="string">"@reduxjs/toolkit"</span></span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">"axios"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建一个异步的action</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> fetchHomeMultidataAction = <span class="title function_">createAsyncThunk</span>(</span><br><span class="line"> <span class="string">"fetch/homemultidata"</span>, </span><br><span class="line"> <span class="comment">// 有传递过来两个个参数, 从store里面解构拿到dispatch</span></span><br><span class="line"> <span class="keyword">async</span> (extraInfo, { dispatch }) => {</span><br><span class="line"> <span class="comment">// 1.发送网络请求获取数据</span></span><br><span class="line"> <span class="keyword">const</span> res = <span class="keyword">await</span> axios.<span class="title function_">get</span>(<span class="string">"http://123.207.32.32:8000/home/multidata"</span>)</span><br><span class="line"> <span class="comment">// 2.从网络请求结果中取出数据</span></span><br><span class="line"> <span class="keyword">const</span> banners = res.<span class="property">data</span>.<span class="property">data</span>.<span class="property">banner</span>.<span class="property">list</span></span><br><span class="line"> <span class="keyword">const</span> recommends = res.<span class="property">data</span>.<span class="property">data</span>.<span class="property">recommend</span>.<span class="property">list</span></span><br><span class="line"> <span class="comment">// 3.执行dispatch, 派发action</span></span><br><span class="line"> <span class="title function_">dispatch</span>(<span class="title function_">changeBanners</span>(banners))</span><br><span class="line"> <span class="title function_">dispatch</span>(<span class="title function_">changeRecommends</span>(recommends))</span><br><span class="line"> }</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> homeSlice = <span class="title function_">createSlice</span>({</span><br><span class="line"> <span class="attr">name</span>: <span class="string">"home"</span>,</span><br><span class="line"> <span class="attr">initialState</span>: {</span><br><span class="line"> <span class="attr">banners</span>: [],</span><br><span class="line"> <span class="attr">recommends</span>: []</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">reducers</span>: {</span><br><span class="line"> <span class="title function_">changeBanners</span>(<span class="params">state, { payload }</span>) {</span><br><span class="line"> state.<span class="property">banners</span> = payload</span><br><span class="line"> },</span><br><span class="line"> <span class="title function_">changeRecommends</span>(<span class="params">state, { payload }</span>) {</span><br><span class="line"> state.<span class="property">recommends</span> = payload</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> { changeBanners, changeRecommends } = homeSlice.<span class="property">actions</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> homeSlice.<span class="property">reducer</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>其他地方引入执行异步</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { useDispatch } <span class="keyword">from</span> <span class="string">"react-redux"</span>;</span><br><span class="line"><span class="keyword">const</span> dispatch = <span class="title function_">useDispatch</span>();</span><br><span class="line"><span class="title function_">dispatch</span>(<span class="title function_">fetchHomeMultidataAction</span>())</span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ul><li><strong>先看看片段</strong><ul><li>projectList.slice.ts</li></ul></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {createSlice} <span class="keyword">from</span> <span class="string">"@reduxjs/toolkit"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> projectListSlice = <span class="title function_">createSlice</span>({</span><br><span class="line"> <span class="attr">name</span>:<span class="string">'projectListSlice'</span>,</span><br><span class="line"> <span class="attr">initialState</span>:{</span><br><span class="line"> <span class="attr">projectModalOpen</span>:<span class="literal">false</span>,</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">reducers</span>:{</span><br><span class="line"> <span class="comment">/* 开启对话框 */</span></span><br><span class="line"> <span class="title function_">openProjectModal</span>(<span class="params">state</span>){</span><br><span class="line"> <span class="comment">//immer帮我们处理了,所以我们可以直接在返回的state书写</span></span><br><span class="line"> state.<span class="property">projectModalOpen</span> = <span class="literal">true</span>;</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">/* 关闭对话框 */</span></span><br><span class="line"> <span class="title function_">closeProjectModal</span>(<span class="params">state</span>){</span><br><span class="line"> state.<span class="property">projectModalOpen</span> = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> projectListSliceReducer = projectListSlice.<span class="property">reducer</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> projectListSliceActions = projectListSlice.<span class="property">actions</span>;</span><br><span class="line"><span class="comment">//获取state,从store当中的reducer获取值</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">selectProjectModalOpen</span> = (<span class="params">state</span>) => state.<span class="property">projectList</span>.<span class="property">projectModalOpen</span>;</span><br></pre></td></tr></table></figure><ul><li><strong>store/index.ts</strong></li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {configureStore} <span class="keyword">from</span> <span class="string">"@reduxjs/toolkit"</span>;</span><br><span class="line"><span class="keyword">import</span> {projectListSliceReducer} <span class="keyword">from</span> <span class="string">"../pages/projectList/projectList.slice"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> store = <span class="title function_">configureStore</span>({</span><br><span class="line"> <span class="comment">/* 设置状态管理 */</span></span><br><span class="line"> <span class="attr">reducer</span>:{</span><br><span class="line"> <span class="attr">projectList</span>:projectListSliceReducer</span><br><span class="line"> },</span><br><span class="line">})</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><p>获取数据使用<code>useSelector (import {useSelector} from "react-redux")</code></p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { useSelector } <span class="keyword">from</span> <span class="string">"react-redux"</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">selectProjectModalOpen</span> = state => state.<span class="property">projectList</span>.<span class="property">projectModalOpen</span>;</span><br><span class="line"><span class="keyword">const</span> showModal = <span class="title function_">useSelector</span>(selectProjectModalOpen);</span><br><span class="line"></span><br><span class="line"><span class="comment">//等同于 const showModal = useSelector((state) => state.projectList.projectModalOpen)</span></span><br></pre></td></tr></table></figure></li><li><p>触发方法使用<code>useDispatch ( import { useDispatch } from "react-redux" )</code></p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { useDispatch } <span class="keyword">from</span> <span class="string">"react-redux"</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> {projectListSliceActions} = <span class="string">"./projectList.slice"</span>;</span><br><span class="line"></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{()</span> =></span> dispatch(projectListSliceActions.closeProjectModal())}>点击我关闭<span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202303051747463.png" alt="可以自己加ts"></p><h2 id="用代码分割优化性能"><a href="#用代码分割优化性能" class="headerlink" title="用代码分割优化性能"></a>用代码分割优化性能</h2><ul><li>react官网说明<ul><li><a target="_blank" rel="noopener" href="https://zh-hans.reactjs.org/docs/code-splitting.html">https://zh-hans.reactjs.org/docs/code-splitting.html</a></li></ul></li><li>使用<code>React.lazy</code><ul><li>需要配合<code>Suspense</code>组件使用,传入<code>fallback</code>参数作为加载时候的画面</li><li>注意组件要使用默认导出</li></ul></li></ul><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">React</span>,{lazy,<span class="title class_">Suspense</span>} <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> {useAuth} <span class="keyword">from</span> <span class="string">"./context/authContext"</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="string">'./App.css'</span>;</span><br><span class="line"><span class="keyword">import</span> {<span class="title class_">Boundary</span>} <span class="keyword">from</span> <span class="string">"./component/errorBoundary"</span>;</span><br><span class="line"><span class="keyword">import</span> {<span class="title class_">FullErrorFallBack</span>, <span class="title class_">FullPageLoading</span>} <span class="keyword">from</span> <span class="string">"./component/lib"</span>;</span><br><span class="line"><span class="comment">//import UnAuthenticated from "./pages/unAuthenticated";</span></span><br><span class="line"><span class="comment">//import Authenticated from "./pages/authenticated";</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">UnAuthenticated</span> = <span class="title function_">lazy</span>(<span class="function">() =></span> <span class="keyword">import</span>(<span class="string">"./pages/unAuthenticated"</span>))</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Authenticated</span> = <span class="title function_">lazy</span>(<span class="function">() =></span> <span class="keyword">import</span>(<span class="string">"./pages/authenticated"</span>))</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">App</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">const</span> {userInfo} = <span class="title function_">useAuth</span>();</span><br><span class="line"> <span class="comment">/*测试错误*/</span></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <span class="language-xml"><span class="tag"><<span class="name">div</span> <span class="attr">className</span>=<span class="string">'App'</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">Boundary</span> <span class="attr">fallBackRender</span>=<span class="string">{FullErrorFallBack}</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"><<span class="name">Suspense</span> <span class="attr">fallback</span>=<span class="string">{FullPageLoading}</span>></span></span></span><br><span class="line"><span class="language-xml"> {</span></span><br><span class="line"><span class="language-xml"> userInfo && Object.keys(userInfo).length ? <span class="tag"><<span class="name">Authenticated</span>/></span> : <span class="tag"><<span class="name">UnAuthenticated</span>/></span></span></span><br><span class="line"><span class="language-xml"> }</span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">Suspense</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">Boundary</span>></span></span></span><br><span class="line"><span class="language-xml"> <span class="tag"></<span class="name">div</span>></span></span></span><br><span class="line"> );</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">App</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="使用React-memo"><a href="#使用React-memo" class="headerlink" title="使用React.memo"></a>使用React.memo</h2><ul><li>使用后,只有当组件的props或者全局状态,比如redux发生变化的时候,才会执行重新渲染</li></ul><h2 id="Profiler"><a href="#Profiler" class="headerlink" title="Profiler"></a>Profiler</h2><ul><li><p>生产环境禁止使用</p><ul><li>如果需要,在编译的时候添加(如果是create react app)创建的话</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">yarn build --profile</span><br><span class="line">npm run build --profile</span><br></pre></td></tr></table></figure></li></ul><h2 id="单元测试-React"><a href="#单元测试-React" class="headerlink" title="单元测试(React)"></a>单元测试(React)</h2><ul><li><p>我们<code>setupWorker</code>以前曾为开发创建了一个假服务器。现在我们使用不同的函数,<code>setupServer</code>因为测试将在 Node.js 环境中运行,而不是在实际的浏览器环境中。只有浏览器环境具有 Service Worker 功能,因此我们在测试中使用 MSW 的方式实际上并不涉及 Service Worker。</p><ul><li>也就是说<code>setupServer</code>在node环境下使用的,不涉及到浏览器,<code>setupWorker</code>在浏览器中运行的</li></ul></li><li><p>最基础的单元测试</p><ul><li>随便哪里建立一个sum函数</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">sum</span>(<span class="params">a, b</span>) {</span><br><span class="line"> <span class="keyword">return</span> a + b;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>src/<strong>tests</strong>/sun.ts文件(其实你取名叫<code>sun.test.ts</code>也可以,其实都会识别)</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {sum} <span class="keyword">from</span> <span class="string">"../utils"</span>;</span><br><span class="line"></span><br><span class="line"><span class="title function_">test</span>(<span class="string">'测试结果是否为100'</span>,<span class="function">() =></span> {</span><br><span class="line"> <span class="title function_">expect</span>(<span class="title function_">sum</span>(<span class="number">50</span>,<span class="number">50</span>)).<span class="title function_">toBe</span>(<span class="number">100</span>)</span><br><span class="line">})</span><br></pre></td></tr></table></figure></li><li><p>然后运行<code>yarn test</code></p><ul><li>可以看到自动去寻找了<code>__tests__</code>当中的文件进行测试</li></ul></li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202303072113418.png"></p><h3 id="先看看msw拦截异步请求的代码怎么写"><a href="#先看看msw拦截异步请求的代码怎么写" class="headerlink" title="先看看msw拦截异步请求的代码怎么写"></a>先看看msw拦截异步请求的代码怎么写</h3><ul><li><p>总的来说就是: <strong>创建handler,使用handler,开始拦截</strong></p></li><li><p><strong>1.创建handler</strong></p></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {rest} <span class="keyword">from</span> <span class="string">"msw"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> handlers = [</span><br><span class="line"> <span class="comment">// 用于登录</span></span><br><span class="line"> rest.<span class="title function_">post</span>(<span class="string">'/login'</span>,<span class="function">(<span class="params">req,res,context</span>) =></span> {</span><br><span class="line"> <span class="variable language_">sessionStorage</span>.<span class="title function_">setItem</span>(<span class="string">'is-authenticated'</span>,<span class="string">'true'</span>);<span class="comment">//设置登录状态为真</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">res</span>(</span><br><span class="line"> context.<span class="title function_">status</span>(<span class="number">200</span>)</span><br><span class="line"> )</span><br><span class="line"> }),</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 用于获取用户信息</span></span><br><span class="line"> rest.<span class="title function_">get</span>(<span class="string">'/user'</span>,<span class="function">(<span class="params">req, res, context</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> isAuthenticated = <span class="variable language_">sessionStorage</span>.<span class="title function_">getItem</span>(<span class="string">'is-authenticated'</span>);</span><br><span class="line"> <span class="comment">//未认证的用户</span></span><br><span class="line"> <span class="keyword">if</span>(!isAuthenticated){</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">res</span>(context.<span class="title function_">status</span>(<span class="number">403</span>),context.<span class="title function_">json</span>({</span><br><span class="line"> <span class="attr">errorMessage</span>:<span class="string">'未进行认证'</span></span><br><span class="line"> }))</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 已经认证的用户</span></span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">res</span>(context.<span class="title function_">status</span>(<span class="number">200</span>),context.<span class="title function_">json</span>({</span><br><span class="line"> <span class="attr">username</span>:<span class="string">'admin'</span>,</span><br><span class="line"> <span class="attr">address</span>:<span class="string">'dreamlove.top'</span></span><br><span class="line"> }))</span><br><span class="line"> }),</span><br><span class="line">]</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>2.使用handler</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { setupWorker,<span class="title class_">SetupWorker</span> } <span class="keyword">from</span> <span class="string">"msw"</span>;</span><br><span class="line"><span class="keyword">import</span> { handlers } <span class="keyword">from</span> <span class="string">"./handler"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="attr">worker</span>:<span class="title class_">SetupWorker</span> = <span class="title function_">setupWorker</span>(...handlers)</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>3.开始拦截(只要匹配到了handler当中的列表,就进行拦截)<ul><li>我访问<code>/login</code>或者<code>/list</code>就会被拦截,从而返回假数据</li></ul></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { worker } <span class="keyword">from</span> <span class="string">"./mocks/browser"</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(<span class="keyword">import</span>.<span class="property">meta</span>.<span class="property">env</span>.<span class="property">DEV</span>){</span><br><span class="line"> <span class="comment">/* 开发环境下就启动 */</span></span><br><span class="line"> worker.<span class="title function_">start</span>();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>演示地址<ul><li>github:<a target="_blank" rel="noopener" href="https://github.com/superBiuBiuMan/mswSimpleStudy">https://github.com/superBiuBiuMan/mswSimpleStudy</a></li><li>codesandbox:<a target="_blank" rel="noopener" href="https://githubbox.com/superBiuBiuMan/mswSimpleStudy">https://githubbox.com/superBiuBiuMan/mswSimpleStudy</a></li></ul></li></ul><h3 id="setupServer和setupWorker"><a href="#setupServer和setupWorker" class="headerlink" title="setupServer和setupWorker"></a>setupServer和setupWorker</h3><ul><li>也就是说<code>setupServer</code>在node环境下使用的,不涉及到浏览器,<code>setupWorker</code>在浏览器中运行的</li><li>老师的代码没有过多解释,我们就以下面代码做个简单说明<ul><li>其实老师大概步骤也和上面msw拦截异步请求代码一样</li><li><strong>先监听,然后拦截,之后才是创建</strong></li></ul></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {setupServer} <span class="keyword">from</span> <span class="string">"msw/node"</span>;</span><br><span class="line"><span class="keyword">import</span> { rest } <span class="keyword">from</span> <span class="string">"msw"</span>;<span class="comment">//用于发送假数据</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> server = <span class="title function_">setupServer</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">//文件内所有测试开始前执行的钩子函数</span></span><br><span class="line"><span class="title function_">beforeAll</span>(<span class="function">() =></span> {</span><br><span class="line"> server.<span class="title function_">listen</span>();</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="comment">//文件内每个测试完成后执行的钩子函数(执行完test之后执行的)</span></span><br><span class="line"><span class="title function_">afterEach</span>(<span class="function">() =></span> {</span><br><span class="line"> server.<span class="title function_">resetHandlers</span>();</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="comment">//文件内所有测试完成后执行的钩子函数</span></span><br><span class="line"><span class="title function_">afterEach</span>(<span class="function">() =></span> {</span><br><span class="line"> server.<span class="title function_">close</span>();</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="title function_">test</span>(<span class="string">'发送异步请求'</span>,<span class="keyword">async</span> () => {</span><br><span class="line"> <span class="comment">/* 其实这一步就是向handler添加数据 */</span></span><br><span class="line"> server.<span class="title function_">use</span>(rest.<span class="title function_">get</span>(<span class="string">'/list'</span>,<span class="function">(<span class="params">req,res,ctx</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">res</span>(ctx.<span class="title function_">status</span>(<span class="number">200</span>),ctx.<span class="title function_">json</span>([</span><br><span class="line"> {<span class="attr">name</span>:<span class="string">'李白1'</span>,<span class="attr">age</span>:<span class="number">18</span>},</span><br><span class="line"> {<span class="attr">name</span>:<span class="string">'李白2'</span>,<span class="attr">age</span>:<span class="number">19</span>},</span><br><span class="line"> {<span class="attr">name</span>:<span class="string">'李白3'</span>,<span class="attr">age</span>:<span class="number">20</span>},</span><br><span class="line"> ]))</span><br><span class="line"> }));</span><br><span class="line"> <span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">'/list'</span>)</span><br><span class="line"> <span class="keyword">const</span> result = <span class="keyword">await</span> response.<span class="title function_">json</span>();</span><br><span class="line"> <span class="title function_">expect</span>(result).<span class="title function_">toEqual</span>([</span><br><span class="line"> {<span class="attr">name</span>:<span class="string">'李白1'</span>,<span class="attr">age</span>:<span class="number">18</span>},</span><br><span class="line"> {<span class="attr">name</span>:<span class="string">'李白2'</span>,<span class="attr">age</span>:<span class="number">19</span>},</span><br><span class="line"> {<span class="attr">name</span>:<span class="string">'李白3'</span>,<span class="attr">age</span>:<span class="number">20</span>},</span><br><span class="line"> ])</span><br><span class="line">})</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>其实很简单,<code>server.use</code>理解为向监视器里面添加东西,添加的东西会被拦截并做处理,只不过我们每次测试完毕,都将里面的handler进行了清空</li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202303072125709.png"></p><h1 id="额外小知识"><a href="#额外小知识" class="headerlink" title="额外小知识"></a>额外小知识</h1><ul><li><p>encodeURIComponent(转义URL当中部分字符的)</p></li><li><p>encodeURI(转移整个URL内容的)</p></li><li><p><code>.env</code>,<code>.env.development</code></p><ul><li>当为<code>npm start</code>的时候.webpack会去读取<code>.env.development</code>文件</li><li>当为<code>npm run build</code>编译之后,webpack会去读取<code>.env.development</code>文件</li><li>并将读取的文件作为一个对象存储在<code>process.env</code>当中</li><li>比如<code>.env.development</code>有如下内容</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">abc = 'www.baidu.com'</span><br></pre></td></tr></table></figure><ul><li>那么我们就可以读取</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">process.env.abc</span><br></pre></td></tr></table></figure><ul><li>如果是vite读取,则需要通过如下来读取,并且设置的变量必须要以<code>VITE_</code>开头</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const apiUrl = import.meta.env</span><br></pre></td></tr></table></figure></li><li><p>遇到这种不明确的情况(比如name=),到底是搜索名字为空的,还是要忽略这种情况呢?所以我们需要在前端做处理</p></li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202301092137442.png"></p><ul><li><p><code>TS7016: Could not find a declaration file for module './screens/projectList'. 'D:/develop/phpstudy_pro/WWW/React-cli/react_17_projectJira/src/screens/projectList/index.jsx' implicitly has an 'any' type.</code>这种报错</p><ul><li>就是缺少声明文件,要么自己添加对应的<code>xxx.d.ts</code>文件或者使用<code>//@ts-ignore</code>进行忽略</li></ul></li><li><p><strong>useHooks(不管是自带的hooks还是自己创建的hooks),不可以在普通函数中运行,只能在hooks当中使用或者其他hooks使用,所以在自定义hooks的时候,需要以useXxx开头</strong></p></li></ul><p><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202301101959551.png"></p></article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta"><i class="fas fa-circle-user fa-fw"></i>文章作者: </span><span class="post-copyright-info"><a href="https://www.dreamlove.top">梦洁</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta"><i class="fas fa-square-arrow-up-right fa-fw"></i>文章链接: </span><span class="post-copyright-info"><a href="https://www.dreamlove.top/36e87c18.html">https://www.dreamlove.top/36e87c18.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta"><i class="fas fa-circle-exclamation fa-fw"></i>版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://www.dreamlove.top" target="_blank">梦洁小站-属于你我的小天地</a>!</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/React/">React</a></div><div class="post_share"><div class="social-share" data-image="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202304091759286.png" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://lib.baomitu.com/butterfly-extsrc/1.1.3/sharejs/dist/css/share.min.css" media="print" onload='this.media="all"'><script src="https://lib.baomitu.com/butterfly-extsrc/1.1.3/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/5978735e.html" title="Ubuntu系统安装基本Nginx和docker和一些其他的软件的基本操作"><img class="cover" src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202304091726513.png" onerror='onerror=null,src="/img/404.png"' alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Ubuntu系统安装基本Nginx和docker和一些其他的软件的基本操作</div></div></a></div><div class="next-post pull-right"><a href="/2192bb69.html" title="vercel和netlify部署代码并解决接口代理转发的问题(和Nginx功能一样)"><img class="cover" src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202304091808028.png" onerror='onerror=null,src="/img/404.png"' alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">vercel和netlify部署代码并解决接口代理转发的问题(和Nginx功能一样)</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/447d3137.html" title="React的学习笔记-(Bilibili天禹老师)"><img class="cover" src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202304091819967.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-02-02</div><div class="title">React的学习笔记-(Bilibili天禹老师)</div></div></a></div><div><a href="/316d79f9.html" title="React的学习笔记-(Bilibili李立超)"><img class="cover" src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202304091818601.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-02-02</div><div class="title">React的学习笔记-(Bilibili李立超)</div></div></a></div><div><a href="/192840d8.html" title="Antd React Form.Item内部是自定义组件怎么自定义返回值"><img class="cover" src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202403181552977.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-11-12</div><div class="title">Antd React Form.Item内部是自定义组件怎么自定义返回值</div></div></a></div><div><a href="/bedba37b.html" title="index.min.js1 Warning value should in shape of { value string number, label ReactNode } when you set labelInValue` to true`"><div class="cover" style="background:var(--default-bg-color)"></div><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2024-01-13</div><div class="title">index.min.js1 Warning value should in shape of { value string number, label ReactNode } when you set labelInValue` to true`</div></div></a></div></div></div><hr class="custom-hr"><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div id="artalk-wrap"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://oss.dreamlove.top/i/2024/02/02/nw24wu.png" onerror='this.onerror=null,this.src="/img/404.png"' alt="avatar"></div><div class="author-info__name">梦洁</div><div class="author-info__description">小小的字,有大大的梦想~分享我的前端学习过程,经历,错误,和一些其他折腾过程</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">168</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">90</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">68</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/superBiuBiuMan"><i class="fab fa-github"></i><span>关注下我(* ̄▽ ̄*)</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="mailto:[email protected]" target="_blank" title="Email"><i class="fas fa-envelope" style="color:#4a7dbe"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">不断更新中,有问题请留言回复(会通过邮箱提醒~)</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%89%8D%E8%A8%80"><span class="toc-number">1.</span> <span class="toc-text">前言</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#REST-API%E9%A3%8E%E6%A0%BC"><span class="toc-number">1.1.</span> <span class="toc-text">REST-API风格</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#json-server"><span class="toc-number">1.2.</span> <span class="toc-text">json-server</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%A7%8B"><span class="toc-number">2.</span> <span class="toc-text">项目开始</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%94%A8jsx%E6%B8%B2%E6%9F%93%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%88%97%E8%A1%A8"><span class="toc-number">2.1.</span> <span class="toc-text">用jsx渲染开发工程列表</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AD%A6%E4%B9%A0%E8%87%AA%E5%AE%9A%E4%B9%89hook"><span class="toc-number">2.2.</span> <span class="toc-text">学习自定义hook</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84useMount%E5%92%8CuseDebounce"><span class="toc-number">2.2.1.</span> <span class="toc-text">使用自定义的useMount和useDebounce</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#js%E6%94%B9%E9%80%A0%E4%B8%BAts"><span class="toc-number">2.2.2.</span> <span class="toc-text">js改造为ts</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%B8%AD%E5%AD%90%E7%B1%BB%E5%9E%8B%E5%92%8Cjson-server%E4%B8%AD%E9%97%B4%E4%BB%B6"><span class="toc-number">2.3.</span> <span class="toc-text">鸭子类型和json-server中间件</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%89%E8%A3%85jira-dev-tool"><span class="toc-number">2.4.</span> <span class="toc-text">安装jira-dev-tool</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89useHttp%E5%A4%84%E7%90%86%E7%99%BB%E5%BD%95%E7%8A%B6%E6%80%81"><span class="toc-number">2.5.</span> <span class="toc-text">使用自定义useHttp处理登录状态</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%9B%B4%E6%94%B9%E4%B8%BAantd"><span class="toc-number">2.6.</span> <span class="toc-text">更改为antd</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8css-in-js-Emotion"><span class="toc-number">2.7.</span> <span class="toc-text">使用css-in-js-Emotion</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#grid%E5%92%8Cflex%E5%90%84%E8%87%AA%E7%9A%84%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-number">2.8.</span> <span class="toc-text">grid和flex各自的应用场景</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#css-in-js-Row%E7%BB%84%E4%BB%B6%E5%AE%9E%E7%8E%B0"><span class="toc-number">2.9.</span> <span class="toc-text">css-in-js:Row组件实现</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%8C%E6%88%90%E9%A1%B9%E7%9B%AE%E5%88%97%E8%A1%A8%E9%A1%B5%E9%9D%A2%E6%A0%B7%E5%BC%8F"><span class="toc-number">2.10.</span> <span class="toc-text">完成项目列表页面样式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B8%85%E9%99%A4%E8%AD%A6%E5%91%8Atodo"><span class="toc-number">2.11.</span> <span class="toc-text">清除警告todo</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%99%BB%E5%BD%95%E6%B3%A8%E5%86%8C%E9%A1%B5%E9%9D%A2loading%E5%92%8Cerror%E7%8A%B6%E6%80%81%E5%A4%84%E7%90%86"><span class="toc-number">2.12.</span> <span class="toc-text">登录注册页面loading和error状态处理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AFtry-catch%E6%98%AF%E5%90%8C%E6%AD%A5%E7%9A%84"><span class="toc-number">2.12.1.</span> <span class="toc-text">需要注意的是try-catch是同步的</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9C%AA%E6%8D%95%E8%8E%B7%E9%94%99%E8%AF%AF-Uncaught-Errors-%E9%94%99%E8%AF%AF%E8%BE%B9%E7%95%8C"><span class="toc-number">2.12.2.</span> <span class="toc-text">未捕获错误(Uncaught Errors)-错误边界</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8useRef%E5%AE%9E%E7%8E%B0useDocumentTitle"><span class="toc-number">2.13.</span> <span class="toc-text">使用useRef实现useDocumentTitle</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8A%A8%E6%80%81%E6%94%B9%E5%8F%98%E7%BD%91%E9%A1%B5%E6%A0%87%E7%AD%BE%E6%98%BE%E7%A4%BA%E7%9A%84%E6%A0%87%E9%A2%98-todo"><span class="toc-number">2.14.</span> <span class="toc-text">动态改变网页标签显示的标题#todo</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B7%BB%E5%8A%A0%E9%A1%B9%E7%9B%AE%E5%88%97%E8%A1%A8%E5%92%8C%E9%A1%B9%E7%9B%AE%E8%AF%A6%E6%83%85"><span class="toc-number">2.15.</span> <span class="toc-text">添加项目列表和项目详情</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#useSearchParams%E5%88%9D%E6%AD%A5%E5%AE%8C%E6%88%90"><span class="toc-number">2.16.</span> <span class="toc-text">useSearchParams初步完成</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#useSearchParams%E5%AE%8C%E6%88%90-%E4%BD%BF%E7%94%A8useMemo%E8%A7%A3%E5%86%B3"><span class="toc-number">2.17.</span> <span class="toc-text">useSearchParams完成(使用useMemo解决)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%8C%E6%88%90%E7%9A%84URL%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86%E4%BB%A3%E7%A0%81"><span class="toc-number">2.18.</span> <span class="toc-text">完成的URL状态管理代码</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0Id-Select%E8%A7%A3%E5%86%B3Id%E9%9A%BE%E9%A2%98"><span class="toc-number">2.19.</span> <span class="toc-text">实现Id-Select解决Id难题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%94%A8useEditProject%E7%BC%96%E8%BE%91%E9%A1%B9%E7%9B%AE"><span class="toc-number">2.20.</span> <span class="toc-text">用useEditProject编辑项目</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9F%AF%E9%87%8C%E5%8C%96"><span class="toc-number">2.20.1.</span> <span class="toc-text">柯里化</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%83%B0%E6%80%A7%E5%88%9D%E5%A7%8B%E5%8C%96%E5%92%8C%E4%BD%BF%E7%94%A8useRef%E4%BF%9D%E5%AD%98%E5%87%BD%E6%95%B0%E5%92%8CuseState%E4%BF%9D%E5%AD%98%E5%87%BD%E6%95%B0%E7%9A%84%E6%96%B9%E6%B3%95"><span class="toc-number">2.20.2.</span> <span class="toc-text">惰性初始化和使用useRef保存函数和useState保存函数的方法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF%E6%83%B0%E6%80%A7%E5%88%9D%E5%A7%8B%E5%8C%96"><span class="toc-number">2.20.2.1.</span> <span class="toc-text">什么是惰性初始化</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#useRef"><span class="toc-number">2.20.2.2.</span> <span class="toc-text">useRef</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#useState%E4%BF%9D%E5%AD%98%E5%87%BD%E6%95%B0%E7%9A%84%E6%96%B9%E6%B3%95"><span class="toc-number">2.20.2.3.</span> <span class="toc-text">useState保存函数的方法</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BC%98%E5%8C%96%E5%BC%82%E6%AD%A5%E8%AF%B7%E6%B1%82"><span class="toc-number">2.21.</span> <span class="toc-text">优化异步请求</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E4%BD%BF%E7%94%A8useMemo-useCallback"><span class="toc-number">2.21.0.1.</span> <span class="toc-text">什么时候使用useMemo,useCallback</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%8A%B6%E6%80%81%E6%8F%90%E5%8D%87"><span class="toc-number">2.22.</span> <span class="toc-text">状态提升</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#useUndo"><span class="toc-number">2.23.</span> <span class="toc-text">useUndo</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#redux"><span class="toc-number">2.24.</span> <span class="toc-text">redux</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#reduxjs-tooltik%E5%92%8Creact-redux"><span class="toc-number">2.25.</span> <span class="toc-text">reduxjs/tooltik和react-redux</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9C%89%E5%85%B3reduxjs-toolkit%E9%83%A8%E5%88%86"><span class="toc-number">2.25.1.</span> <span class="toc-text">有关reduxjs/toolkit部分</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9C%89%E5%85%B3react-redux"><span class="toc-number">2.25.2.</span> <span class="toc-text">有关react-redux</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8"><span class="toc-number">2.25.3.</span> <span class="toc-text">使用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%89%A7%E8%A1%8C%E5%BC%82%E6%AD%A5"><span class="toc-number">2.25.4.</span> <span class="toc-text">执行异步</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%96%B9%E6%B3%951"><span class="toc-number">2.25.4.1.</span> <span class="toc-text">方法1:</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%96%B9%E6%B3%952"><span class="toc-number">2.25.4.2.</span> <span class="toc-text">方法2</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-number">2.25.5.</span> <span class="toc-text">总结</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%94%A8%E4%BB%A3%E7%A0%81%E5%88%86%E5%89%B2%E4%BC%98%E5%8C%96%E6%80%A7%E8%83%BD"><span class="toc-number">2.26.</span> <span class="toc-text">用代码分割优化性能</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%BF%E7%94%A8React-memo"><span class="toc-number">2.27.</span> <span class="toc-text">使用React.memo</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Profiler"><span class="toc-number">2.28.</span> <span class="toc-text">Profiler</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95-React"><span class="toc-number">2.29.</span> <span class="toc-text">单元测试(React)</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%88%E7%9C%8B%E7%9C%8Bmsw%E6%8B%A6%E6%88%AA%E5%BC%82%E6%AD%A5%E8%AF%B7%E6%B1%82%E7%9A%84%E4%BB%A3%E7%A0%81%E6%80%8E%E4%B9%88%E5%86%99"><span class="toc-number">2.29.1.</span> <span class="toc-text">先看看msw拦截异步请求的代码怎么写</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#setupServer%E5%92%8CsetupWorker"><span class="toc-number">2.29.2.</span> <span class="toc-text">setupServer和setupWorker</span></a></li></ol></li></ol><li class="toc-item toc-level-1"><a class="toc-link" href="#%E9%A2%9D%E5%A4%96%E5%B0%8F%E7%9F%A5%E8%AF%86"><span class="toc-number">3.</span> <span class="toc-text">额外小知识</span></a></li></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/50575b3e.html" title="独角数卡,打开商品列表出现Undefined variable form的解决办法"><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202408241535616.png" onerror='this.onerror=null,this.src="/img/404.png"' alt="独角数卡,打开商品列表出现Undefined variable form的解决办法"></a><div class="content"><a class="title" href="/50575b3e.html" title="独角数卡,打开商品列表出现Undefined variable form的解决办法">独角数卡,打开商品列表出现Undefined variable form的解决办法</a><time datetime="2024-08-24T15:31:38.000Z" title="发表于 2024-08-24 15:31:38">2024-08-24</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/6ace453b.html" title="前端常用npm库大全-vue,react,通用(持续更新)"><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202408241528979.png" onerror='this.onerror=null,this.src="/img/404.png"' alt="前端常用npm库大全-vue,react,通用(持续更新)"></a><div class="content"><a class="title" href="/6ace453b.html" title="前端常用npm库大全-vue,react,通用(持续更新)">前端常用npm库大全-vue,react,通用(持续更新)</a><time datetime="2024-08-24T15:24:59.000Z" title="发表于 2024-08-24 15:24:59">2024-08-24</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/f4cb1979.html" title="基于vue-pdf-embed的二开PDF预览的通用组件"><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202408241539662.png" onerror='this.onerror=null,this.src="/img/404.png"' alt="基于vue-pdf-embed的二开PDF预览的通用组件"></a><div class="content"><a class="title" href="/f4cb1979.html" title="基于vue-pdf-embed的二开PDF预览的通用组件">基于vue-pdf-embed的二开PDF预览的通用组件</a><time datetime="2024-08-11T08:53:00.000Z" title="发表于 2024-08-11 08:53:00">2024-08-11</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/84b2339c.html" title="x64dbg反汇编技术入门学习笔记"><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202407311704593.png" onerror='this.onerror=null,this.src="/img/404.png"' alt="x64dbg反汇编技术入门学习笔记"></a><div class="content"><a class="title" href="/84b2339c.html" title="x64dbg反汇编技术入门学习笔记">x64dbg反汇编技术入门学习笔记</a><time datetime="2024-07-31T16:51:01.000Z" title="发表于 2024-07-31 16:51:01">2024-07-31</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/30ebed6d.html" title="linux普通服务器和NAT服务器下载transmission制作种子"><img src="https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202407311703454.png" onerror='this.onerror=null,this.src="/img/404.png"' alt="linux普通服务器和NAT服务器下载transmission制作种子"></a><div class="content"><a class="title" href="/30ebed6d.html" title="linux普通服务器和NAT服务器下载transmission制作种子">linux普通服务器和NAT服务器下载transmission制作种子</a><time datetime="2024-07-31T16:50:14.000Z" title="发表于 2024-07-31 16:50:14">2024-07-31</time></div></div></div></div></div></div></main><footer id="footer" style="background-image:url(https://dreamos.oss-cn-beijing.aliyuncs.com/gitblog/202304091759286.png)"><div id="footer-wrap"><div class="copyright">©2021 - 2024 By 梦洁</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js?v=4.13.0"></script><script src="/js/main.js?v=4.13.0"></script><script src="https://lib.baomitu.com/fancyapps-ui/5.0.33/fancybox/fancybox.umd.min.js"></script><div class="js-pjax"><script>(()=>{let t=null;const e=()=>{if(t=Artalk.init(Object.assign({el:"#artalk-wrap",server:"https://artalk.dreamlove.top",site:"梦洁小站",pageKey:location.pathname,darkMode:"dark"===document.documentElement.getAttribute("data-theme")},null)),"null"===GLOBAL_CONFIG.lightbox)return;t.on("list-loaded",()=>{t.ctx.get("list").getCommentNodes().forEach(t=>{const e=t.getRender().$content;btf.loadLightbox(e.querySelectorAll("img:not([atk-emoticon])"))})});btf.addGlobalFn("pjax",()=>{t.destroy()},"destroyArtalk")},a=async()=>{"object"==typeof Artalk||(await getCSS("https://lib.baomitu.com/artalk/2.8.2/Artalk.min.css"),await getScript("https://lib.baomitu.com/artalk/2.8.2/Artalk.min.js")),e()};btf.addGlobalFn("themeChange",e=>{const a=document.getElementById("artalk-wrap");if(!a||!a.children.length)return;const l="dark"===e;t.setDarkMode(l)},"artalk"),a()})()</script></div><script id="canvas_nest" defer color="0,0,255" opacity="0.7" zindex="-1" count="99" mobile="false" src="https://lib.baomitu.com/butterfly-extsrc/1.1.3/canvas-nest.min.js"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="algolia-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="search-wrap"><div id="algolia-search-input"></div><hr><div id="algolia-search-results"><div id="algolia-hits"></div><div id="algolia-pagination"></div><div id="algolia-info"><div class="algolia-stats"></div><div class="algolia-poweredBy"></div></div></div></div></div><div id="search-mask"></div><script src="https://lib.baomitu.com/algoliasearch/4.22.1/algoliasearch-lite.umd.min.js"></script><script src="https://lib.baomitu.com/instantsearch.js/4.65.0/instantsearch.production.min.js"></script><script src="/js/search/algolia.js?v=4.13.0"></script></div></div></body></html>