前言
專案到一段落,先來記錄一下,本文以前端新手的角度記錄React、TypeScript、Taro相關技術的開發體驗以及遇到的問題和解決方法。
之前總說要學React(這篇部落格:程式碼使我頭疼之React初學習),這次專案需要做H5前端+小程式,我終於能用上React了~
使用React的開發框架之前就聽過京東的Taro,所以就這個了,直接開碼。
關於React
不錯,感覺比Vue的模板寫法自由很多,我看Taro文件的例子都是class元件,但一開始「前端帶師」就推薦我用function元件,現在我全都是用function元件,react就該這麼寫,真香~
因為之前寫了一段時間的Flutter,所以react對我來說很親切,至少可以無縫上手宣告式UI的寫法。
不過我感覺React的生態太大,更新太快了,有點碎片化,很多第三方庫官方文件都跟不上更新速度(批評一下mobx,害人不淺)
話說一開始我看了某位知乎大V的那本React和Redux的書,應該是我太菜的原因,感覺不是很容易理解,果然技術厲害的大佬不一定教書也厲害嗎~
參考資料
- React 入門 - 從js的角度理解 react:https://github.com/coppyC/blog/issues/16
關於TypeScript
第一次用TypeScript,不過作為日常用C#寫後端的人,又處處是熟悉的感覺~
反正比JS好用一萬倍就是了,型別提示真是太棒了
目前用得不深,後續有什麼相關的我再寫寫部落格記錄一下。
參考資料
- 探索 TypeScript 型別註解 - 自定義型別:https://github.com/WowBar/blog/issues/9
Taro框架使用感受
框架是個好框架,不過文件方面感覺還不是很完善,有些地方寫得不是很清楚,感覺很多文件都是複製了微信小程式的文件來的,對於沒開發過微信小程式且沒讀過微信官方文件的人來說,不是很友好。(不過官方文件還是要看,不看的話遇到很多問題都查不到的)
然後Taro官方提供了一個UI庫,叫 TaroUI,用的話還是能用的,就是更新太慢了,它的github專案主頁 顯示上次更新時間還是去年(2021年)6月份,到現在近一年時間沒動過了。最新穩定版本還在2.x,而Taro框架已經更新到3版本了。
因為我用的Taro框架是3.x版本,所以只能硬著頭皮上TaroUI 3的beta版本,導致遇到了一些奇奇怪怪的問題,頭大。
除了TaroUI這個介面庫,Taro官方還提供另一個叫 NutUI 的庫,不過是基於Vue的,我這個專案沒法用,這個庫就更新挺勤快的,github上最近更新還是6小時前,Star也有4.2k,比TaroUI的3.9k多。~~(看來React在京東不受待見呀)~。
我還看到有一個叫 Taroify 的UI庫,看起來好像不錯,更新也很勤快,不過GitHub Stars只有300多,不敢用~ 下次來試試看
用的同時我還參考了這些專案/程式碼/文件:
- https://github.com/NervJS/taro-v2ex/blob/react/src/pages/thread_detail/thread_detail.tsx
- https://github.com/wuba/Taro-Mortgage-Calculator
- https://github.com/NervJS/awesome-taro
接下來進入正題,總體說說遇到的一些問題/坑,以及解決方案。
頁面路由問題
Taro封裝了路由相關的方法,我是做完了專案有時間去翻一下 微信小程式文件 才發現這玩意跟小程式的路由特別像。
PS:我討厭這種路由設計,不知道小程式這樣是哪個人才想出來的,頁面多了的話不太好維護啊~
在 app.config.ts
檔案裡把路由配置好,類似這樣:
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'
},
})
然後要跳轉的地方就用 Taro.navigateTo({url: 'pages/user/login'})
就行了
這裡有個很坑的地方!Taro的熱更新不完善,新增了新頁面後熱更新是不生效的,必須 yarn dev:h5
重啟才能看到效果,一開始我被坑得嗷嗷叫~
地址引數問題
這個問題在我之前的部落格:Django + Taro 前後端分離專案實現企業微信登入 有提到,Taro本身提供了 useRouter()
來給我們讀取地址裡的引數
比如上面那個路由跳轉的地方我們加上了引數: Taro.navigateTo({url: 'pages/user/login?title=hello'})
那我們在 pages/user/login
頁面裡要獲取引數就是這樣
import {useEffect} from "react"
import {useRouter} from "@tarojs/taro"
export default function () {
const router = useRouter()
useEffect(() => {
console.log(router.params.title)
}, [])
}
但當在讀取微信登入伺服器回撥引數的時候,就不行,就取不出來,得自己拿完整連結 window.location.href
去匹配。詳見我這篇部落格:Django + Taro 前後端分離專案實現企業微信登入
Taro.relaunch不會清除URL
這看起來不是什麼大問題,不過也導致了一個小bug,就是我在使用微信登入後,登出登入的時候不會清除地址裡的code,這樣沒關閉頁面的情況下,再次使用微信登入,那個code還是舊的,就直接報錯了~
TaroUI form的bug
說實話我不知道這是哪裡的問題
只有一個頁面出現了這個問題,在最後一個輸入框按回車,表現是form提交,但其實也沒提交,並且頁面變成重新重新整理了
百思不得其解
我只好在最後面再加了一個隱藏的input
<AtInput
name='hide'
onChange={() => {
}}
disabled={true}
border={false}
style={{display: 'none'}}/>
網路請求封裝
Taro框架自帶了 Taro.request
可以用來請求,不過我用的時候很奇怪一直提示跨域,因為前期時間很趕,我就沒去深入,直接換成我之前vue專案封裝好的axios,果然還是axios好用~
(不過之後做成小程式的話,應該還是得重構一下,據說小程式不支援formdata)
封裝useState
感謝「前端帶師 coppy」提供的程式碼~
import {useState} from 'react'
export default function useYourState<T extends {}>(state: T): [T, (state: Partial<T>) => void] {
const [_state, _setState] = useState(state);
return [
_state,
(state: Partial<T>) => {
_setState((_state) => {
return {
..._state,
...state
};
});
}
];
}
這樣就不需要每次setState都需要加...state
了
使用前:
import {useState} from 'react'
export const LoginPage = observer(() => {
const [state, setState] = useState({
username: '',
password: '',
})
setState({
...state,
username: '', password: ''
})
}
使用後:
import useYourState from "@/utils/coppy_state";
export const LoginPage = observer(() => {
const [state, setState] = useYourState({
username: '',
password: '',
})
setState({
username: '', password: ''
})
}
生產力獲得了提高~
全域性狀態管理
沒去用大名鼎鼎的redux,轉而使用比較簡單的mobx
但是找到的例子文件都不太行(舉例,官方中文文件:https://cn.mobx.js.org/)
最終還是尋求「前端帶師」的幫助,搞定了
坑點:
- store現在沒法用裝飾器了,用這個
makeAutoObservable
- 不需要全域性provider
- Taro官網和例子可以說是史上最坑,千萬別被騙了,地址:https://taro-docs.jd.com/taro/docs/mobx/
- 請用最新版的mobx和
mobx-react-lite
,別用Taro官網那個4.8版本,太老了沒用
程式碼
不需要全域性provider包裝了,直接用全域性變數,當然也可以用React Context
store定義
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()
元件使用
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(() => {
useEffect(() => {
if (!myUserStore.isLogin) {
Taro.redirectTo({url: '/pages/user/login'})
}
}, [])
return (
<View className='py-3 px-2'>
<View className='at-article__h1'>使用者中心</View>
<View className='at-article__h3 mt-1'>使用者名稱:{myUserStore.user?.first_name}</View>
<AtButton className='mt-3' onClick={logout}>退出登入</AtButton>
</View>
)
function logout() {
myUserStore.logout()
Taro.reLaunch({url: '/pages/index/index'})
}
})
export default UserPage
參考資料
- 官網文件:https://mobx.js.org/react-integration.html
- 專案地址:https://github.com/mobxjs/mobx/tree/main/packages/mobx-react
- Mobx React 初學者入門指南(掘金):https://juejin.cn/post/6844903831726211079
- mobx 在 react 中的 類元件、函式元件、配合 hooks 的使用:https://juejin.cn/post/6873794258743066632#heading-2
JSON反序列化class
使用這個庫:https://github.com/typestack/class-transformer
model定義,這個定義可以用JSON來生成,有很多線上工具,比如:https://apihelper.jccore.cn/jsontool
export class User {
username: string
first_name: string
last_name: string
email: string
date_joined: string
}
注意專案主頁上的文件也是過期了的,plainToClass
方法已過期,得用這個方法:plainToInstance
import {plainToInstance} from "class-transformer";
const user = plainToInstance(User, res.data.user)
myUserStore.login(user, res.data.token)