冬宝不乖不听话 發表於 2022-4-14 18:07:00

React + TypeScript + Taro前端开发小结

<h2 id="前言">前言</h2>
<p>项目到一段落,先来记录一下,本文以前端新手的角度记录React、TypeScript、Taro相关技术的开发体验以及遇到的问题和解决方法。</p>
<p>之前总说要学React(这篇博客:代码使我头疼之React初学习),这次项目需要做H5前端+小程序,我终于能用上React了~</p>
<p>使用React的开发框架之前就听过京东的Taro,所以就这个了,直接开码。</p>
<h2 id="关于react">关于React</h2>
<p>不错,感觉比Vue的模板写法自由很多,我看Taro文档的例子都是class组件,但一开始「前端带师」就推荐我用function组件,现在我全都是用function组件,react就该这么写,真香~</p>
<p>因为之前写了一段时间的Flutter,所以react对我来说很亲切,至少可以无缝上手声明式UI的写法。</p>
<p>不过我感觉React的生态太大,更新太快了,有点碎片化,很多第三方库官方文档都跟不上更新速度(批评一下mobx,害人不浅)</p>
<p>话说一开始我看了某位知乎大V的那本React和Redux的书,应该是我太菜的原因,感觉不是很容易理解,果然技术厉害的大佬不一定教书也厉害吗~</p>
<h2 id="参考资料">参考资料</h2>
<ul>
<li>React 入门 - 从js的角度理解 react:https://github.com/coppyC/blog/issues/16</li>
</ul>
<h2 id="关于typescript">关于TypeScript</h2>
<p>第一次用TypeScript,不过作为日常用C#写后端的人,又处处是熟悉的感觉~</p>
<p>反正比JS好用一万倍就是了,类型提示真是太棒了</p>
<p>目前用得不深,后续有什么相关的我再写写博客记录一下。</p>
<h3 id="参考资料-1">参考资料</h3>
<ul>
<li>探索 TypeScript 类型注解 - 自定义类型:https://github.com/WowBar/blog/issues/9</li>
</ul>
<h2 id="taro框架使用感受">Taro框架使用感受</h2>
<p>框架是个好框架,不过文档方面感觉还不是很完善,有些地方写得不是很清楚,感觉很多文档都是复制了微信小程序的文档来的,对于没开发过微信小程序且没读过微信官方文档的人来说,不是很友好。(不过官方文档还是要看,不看的话遇到很多问题都查不到的)</p>
<p>然后Taro官方提供了一个UI库,叫 TaroUI,用的话还是能用的,就是更新太慢了,它的github项目主页 显示上次更新时间还是去年(2021年)6月份,到现在近一年时间没动过了。最新稳定版本还在2.x,而Taro框架已经更新到3版本了。</p>
<p>因为我用的Taro框架是3.x版本,所以只能硬着头皮上TaroUI 3的beta版本,导致遇到了一些奇奇怪怪的问题,头大。</p>
<p>除了TaroUI这个界面库,Taro官方还提供另一个叫 NutUI 的库,不过是基于Vue的,我这个项目没法用,这个库就更新挺勤快的,github上最近更新还是6小时前,Star也有4.2k,比TaroUI的3.9k多。~~(看来React在京东不受待见呀<sub>)</sub>~。</p>
<p>我还看到有一个叫 Taroify 的UI库,看起来好像不错,更新也很勤快,不过GitHub Stars只有300多,不敢用~ 下次来试试看</p>
<p>用的同时我还参考了这些项目/代码/文档:</p>
<ul>
<li>https://github.com/NervJS/taro-v2ex/blob/react/src/pages/thread_detail/thread_detail.tsx</li>
<li>https://github.com/wuba/Taro-Mortgage-Calculator</li>
<li>https://github.com/NervJS/awesome-taro</li>
</ul>
<p>接下来进入正题,总体说说遇到的一些问题/坑,以及解决方案。</p>
<h2 id="页面路由问题">页面路由问题</h2>
<p>Taro封装了路由相关的方法,我是做完了项目有时间去翻一下 微信小程序文档 才发现这玩意跟小程序的路由特别像。</p>
<blockquote>
<p>PS:我讨厌这种路由设计,不知道小程序这样是哪个人才想出来的,页面多了的话不太好维护啊~</p>
</blockquote>
<p>在 <code>app.config.ts</code> 文件里把路由配置好,类似这样:</p>
<pre><code class="language-typescript">export default defineAppConfig({
pages: [
    'pages/index/index',
    'pages/info/place',
    'pages/supply/index',
    'pages/user/login',
],
window: {
    backgroundTextStyle: 'light',
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: 'WeChat',
    navigationBarTextStyle: 'black'
},
})
</code></pre>
<p>然后要跳转的地方就用 <code>Taro.navigateTo({url: 'pages/user/login'})</code> 就行了</p>
<p>这里有个很坑的地方!Taro的热更新不完善,添加了新页面后热更新是不生效的,必须 <code>yarn dev:h5</code> 重启才能看到效果,一开始我被坑得嗷嗷叫~</p>
<h2 id="地址参数问题">地址参数问题</h2>
<p>这个问题在我之前的博客:Django + Taro 前后端分离项目实现企业微信登录 有提到,Taro本身提供了 <code>useRouter()</code> 来给我们读取地址里的参数</p>
<p>比如上面那个路由跳转的地方我们加上了参数: <code>Taro.navigateTo({url: 'pages/user/login?title=hello'})</code></p>
<p>那我们在 <code>pages/user/login</code> 页面里要获取参数就是这样</p>
<pre><code class="language-typescript">import {useEffect} from "react"
import {useRouter} from "@tarojs/taro"

export default function () {
    const router = useRouter()
   
    useEffect(() =&gt; {
      console.log(router.params.title)
    }, [])
}
</code></pre>
<p>但当在读取微信登录服务器回调参数的时候,就不行,就取不出来,得自己拿完整链接 <code>window.location.href</code> 去匹配。详见我这篇博客:Django + Taro 前后端分离项目实现企业微信登录</p>
<h2 id="tarorelaunch不会清除url">Taro.relaunch不会清除URL</h2>
<p>这看起来不是什么大问题,不过也导致了一个小bug,就是我在使用微信登录后,注销登录的时候不会清除地址里的code,这样没关闭页面的情况下,再次使用微信登录,那个code还是旧的,就直接报错了~</p>
<h2 id="taroui-form的bug">TaroUI form的bug</h2>
<p>说实话我不知道这是哪里的问题</p>
<p>只有一个页面出现了这个问题,在最后一个输入框按回车,表现是form提交,但其实也没提交,并且页面变成重新刷新了</p>
<p>百思不得其解</p>
<p>我只好在最后面再加了一个隐藏的input</p>
<pre><code class="language-tsx">&lt;AtInput
    name='hide'
    onChange={() =&gt; {
    }}
    disabled={true}
    border={false}
    style={{display: 'none'}}/&gt;
</code></pre>
<h2 id="网络请求封装">网络请求封装</h2>
<p>Taro框架自带了 <code>Taro.request</code> 可以用来请求,不过我用的时候很奇怪一直提示跨域,因为前期时间很赶,我就没去深入,直接换成我之前vue项目封装好的axios,果然还是axios好用~</p>
<p>(不过之后做成小程序的话,应该还是得重构一下,据说小程序不支持formdata)</p>
<h2 id="封装usestate">封装useState</h2>
<p>感谢「前端带师 coppy」提供的代码~</p>
<pre><code class="language-ts">import {useState} from 'react'

export default function useYourState&lt;T extends {}&gt;(state: T): {
const = useState(state);
return [
    _state,
    (state: Partial&lt;T&gt;) =&gt; {
      _setState((_state) =&gt; {
      return {
          ..._state,
          ...state
      };
      });
    }
];
}
</code></pre>
<p>这样就不需要每次setState都需要加<code>...state</code>了</p>
<p>使用前:</p>
<pre><code class="language-js">import {useState} from 'react'

export const LoginPage = observer(() =&gt; {
const = useState({
    username: '',
    password: '',
})

setState({
      ...state,
      username: '', password: ''
})
}
</code></pre>
<p>使用后:</p>
<pre><code class="language-typescript">import useYourState from "@/utils/coppy_state";

export const LoginPage = observer(() =&gt; {
const = useYourState({
    username: '',
    password: '',
})

setState({
      username: '', password: ''
})
}
</code></pre>
<p>生产力获得了提高~</p>
<h2 id="全局状态管理">全局状态管理</h2>
<p>没去用大名鼎鼎的redux,转而使用比较简单的mobx</p>
<p>但是找到的例子文档都不太行(举例,官方中文文档:https://cn.mobx.js.org/)</p>
<p>最终还是寻求「前端带师」的帮助,搞定了</p>
<h3 id="坑点">坑点:</h3>
<ul>
<li>store现在没法用装饰器了,用这个<code>makeAutoObservable</code></li>
<li>不需要全局provider</li>
<li>Taro官网和例子可以说是史上最坑,千万别被骗了,地址:https://taro-docs.jd.com/taro/docs/mobx/</li>
<li>请用最新版的mobx和<code>mobx-react-lite</code>,别用Taro官网那个4.8版本,太老了没用</li>
</ul>
<h3 id="代码">代码</h3>
<p>不需要全局provider包装了,直接用全局变量,当然也可以用React Context</p>
<p>store定义</p>
<pre><code class="language-typescript">import {makeAutoObservable} from "mobx";
import {User} from "@/models/user";
import * as auth from '@/utils/auth'

export class UserStore {
isLogin = false
user: User | null = null
token = ''

constructor() {
    makeAutoObservable(this)
}

login(user: User, token: string) {
    this.user = user
    this.token = token
    this.isLogin = true

    // 保存登录数据到本地
    auth.login(token, user.username)
}

logout() {
    this.isLogin = false
    this.user = null
    this.token = ''

    auth.logout()
}
}

export const myUserStore = new UserStore()
</code></pre>
<p>组件使用</p>
<pre><code class="language-tsx">import {View} from "@tarojs/components"
import {AtButton} from "taro-ui";
import {observer} from "mobx-react-lite";
import {myUserStore} from "@/store/user";
import Taro from "@tarojs/taro";
import {useEffect} from "react";

export const UserPage = observer(() =&gt; {
useEffect(() =&gt; {
    if (!myUserStore.isLogin) {
      Taro.redirectTo({url: '/pages/user/login'})
    }
}, [])

return (
    &lt;View className='py-3 px-2'&gt;
      &lt;View className='at-article__h1'&gt;用户中心&lt;/View&gt;

      &lt;View className='at-article__h3 mt-1'&gt;用户名:{myUserStore.user?.first_name}&lt;/View&gt;

      &lt;AtButton className='mt-3' onClick={logout}&gt;退出登录&lt;/AtButton&gt;
    &lt;/View&gt;
)

function logout() {
    myUserStore.logout()
    Taro.reLaunch({url: '/pages/index/index'})
}
})

export default UserPage
</code></pre>
<h3 id="参考资料-2">参考资料</h3>
<ul>
<li>官网文档:https://mobx.js.org/react-integration.html</li>
<li>项目地址:https://github.com/mobxjs/mobx/tree/main/packages/mobx-react</li>
<li>Mobx React 初学者入门指南(掘金):https://juejin.cn/post/6844903831726211079</li>
<li>mobx 在 react 中的 类组件、函数组件、配合 hooks 的使用:https://juejin.cn/post/6873794258743066632#heading-2</li>
</ul>
<h2 id="json反序列化class">JSON反序列化class</h2>
<p>使用这个库:https://github.com/typestack/class-transformer</p>
<p>model定义,这个定义可以用JSON来生成,有很多在线工具,比如:https://apihelper.jccore.cn/jsontool</p>
<pre><code class="language-typescript">export class User {
username: string
first_name: string
last_name: string
email: string
date_joined: string
}
</code></pre>
<p>注意项目主页上的文档也是过期了的,<code>plainToClass</code>方法已过期,得用这个方法:<code>plainToInstance</code></p>
<pre><code class="language-typescript">import {plainToInstance} from "class-transformer";

const user = plainToInstance(User, res.data.user)
myUserStore.login(user, res.data.token)
</code></pre>


</div>
<div id="MySignature" role="contentinfo">
    微信公众号:「程序设计实验室」
专注于互联网热门新技术探索与团队敏捷开发实践,包括架构设计、机器学习与数据分析算法、移动端开发、Linux、Web前后端开发等,欢迎一起探讨技术,分享学习实践经验。<br><br>
来源:https://www.cnblogs.com/deali/p/16145924.html
頁: [1]
查看完整版本: React + TypeScript + Taro前端开发小结