React + TypeScript + Taro前端開發小結


前言

項目到一段落,先來記錄一下,本文以前端新手的角度記錄React、TypeScript、Taro相關技術的開發體驗以及遇到的問題和解決方法。

之前總說要學React(這篇博客:代碼使我頭疼之React初學習),這次項目需要做H5前端+小程序,我終於能用上React了~

使用React的開發框架之前就聽過京東的Taro,所以就這個了,直接開碼。

關於React

不錯,感覺比Vue的模板寫法自由很多,我看Taro文檔的例子都是class組件,但一開始「前端帶師」就推薦我用function組件,現在我全都是用function組件,react就該這么寫,真香~

因為之前寫了一段時間的Flutter,所以react對我來說很親切,至少可以無縫上手聲明式UI的寫法。

不過我感覺React的生態太大,更新太快了,有點碎片化,很多第三方庫官方文檔都跟不上更新速度(批評一下mobx,害人不淺)

話說一開始我看了某位知乎大V的那本React和Redux的書,應該是我太菜的原因,感覺不是很容易理解,果然技術厲害的大佬不一定教書也厲害嗎~

參考資料

關於TypeScript

第一次用TypeScript,不過作為日常用C#寫后端的人,又處處是熟悉的感覺~

反正比JS好用一萬倍就是了,類型提示真是太棒了

目前用得不深,后續有什么相關的我再寫寫博客記錄一下。

參考資料

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多,不敢用~ 下次來試試看

用的同時我還參考了這些項目/代碼/文檔:

接下來進入正題,總體說說遇到的一些問題/坑,以及解決方案。

頁面路由問題

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

參考資料

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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM