0%

前言

雖然我是覺得在學好一件事情之前不要亂學其他東西另闢戰場
但現實就是永遠有學不完的東西
也永遠沒有學好一件事情的時候
誰知道我會突然又需要學起 python 呢

事情是這樣
最近稍微熟悉一下 RWD 和 React 之後
我就開始動工 react 版本的 TAN 了
做著做著我便開始思考要怎麼簡化網頁的更新流程

目前的做法是每次收到老師的郵件,我就要手動進到伺服器去改檔案
雖然熟了操作起來還蠻快的,但還是有些麻煩而且有可能會東漏西漏
原本更慘,在我剛接手這個網站的時候
除了要打開每一份 html 檔更改標籤
還要手動做篩選,必須自己決定每個 issue 是被歸類在什麼類別
是後來我改用 javascript 選擇性 render html tag
才讓更新網站的速度變得比較能夠接受
但終究我還是需要 ssh 進到伺服器然後把檔案傳上去

所以現在,我打算再更簡化一些
開發一個 api 架在雲端
只要進行 POST request 就能直接更新檔案
然後 react 端就只要 GET 接著渲染出來就好

這代表我要學做 api 啦!!!

該選什麼框架?

一開始我就遇到了二選一
記得之前hahow的老師建議我可以用 python 寫 api
所以我查了一下有一個適合的模組 Flask
但後來我又發現有一個 Express.js
可以讓我用 javascript 寫 api
這讓我有點猶豫 (畢竟我現在 JS 比 python 熟很多)

但最後我選了 flask
正是因為 python 已經漸漸被我淡忘了
如果再不找機會練習的話,真的就要變回一張白紙了
那麼以下就是我建立第一個 flask API 的心路歷程

我會把步驟拆成:

  1. 前置作業
  2. 撰寫 API
  3. 連接 database

前置作業

建立專案資料夾並進入

1
mkdir my-first-flask-api

這次決定自建API,也終於讓我知道虛擬環境的概念
基本上它就像是 node 專案裡的 node_module 資料夾
存放一些專案的 dependency
只不過跟node不同的是
node每個專案都有獨立的環境,所以不同專案間的依賴是互不影響的
但 python 就比較複雜,如果直接 pip 安裝任何模組
他們會被裝在 ...python/lib/site-packages... 之類的地方
有點像 global install 的感覺
但其實沒那麼簡單,因為 python 又可以同時存在好幾個版本
結果就是各個專案間互相牽制,造成一堆問題

所以我們先來建置虛擬環境!
在眾多模組當中我選了 virtualenv 這個模組

首先 pip 安裝

pip install virtualenv

對於什麼時候要用 pip 安裝,什麼時候要用 pip3,之後我再寫一篇短文紀錄好了
大部分時候先用 pip 是 ok 的
有問題時再試 pip3

安裝好後執行以下指令,以在專案資料夾中建立一個虛擬環境資料夾

virtualenv .venv

他會根據你的作業系統
建立不同結構的.venv資料夾

啟用虛擬環境

Windows

如果用 cmd
.\.venv\Scripts\activate.bat

如果用 powershell (VScode是用這個)
.\.venv\Scripts\activate.ps1

. .\.venv\Scripts\activate

MacOS

source ./.venv/bin/activate

. ./.venv/bin/activate

執行完如果在命令列的最開頭看到 (.venv)
就代表成功了

接下來安裝本次最重要的模組 Flask

pip install flask

完成後可以輸入 pip show flask
檢查模組是否如期被安裝在 .venv 虛擬環境中
如果在這之前沒有先啟用虛擬環境的話
flask 就會被安裝在 site-package 那裏

安裝完所需的模組後執行:
pip freeze > requirements.txt

pip freeze 有點像為目前的開發環境拍張 snapshot
紀錄所使用的模組有哪些
就好像凍結這一瞬間一樣(莫名有點浪漫?)
後面的 > 代表要把左側的輸出值寫入右側的檔案
也就是 requirements.txt

這是為了讓其他人 clone 這份專案後能夠以
pip install -r requirements.txt (-r: –requirement)
安裝專案所需的模組

這邊要注意,最好是使用複數的 requirements
雖然打什麼檔名都可以 pip install -r
但有些時候會嚴格檢查(如Heroku)
所以還是要照規矩來比較好

撰寫API

我們建立一個 python file app.py

1
2
3
4
5
6
from flask import Flask

app = Flask(__name__)

if __name__ == "__main__": # 當這份程式被作為主程式執行時
app.run(debug=Ture) # 執行app,debug=True會讓app處於監聽狀態

接著我們建立根路徑

1
2
3
@app.route('/') # Decorator。 在這個路徑下接收到 request (預設為GET) 的話要做以下的事
def index():
return "Hello world from Flask"

目前整個程式非常單純
就是引入flask後啟動它
並設定當根路徑獲得GET請求時要回傳什麼資訊

接下來我們回到 terminal
執行 python app.py
便能開啟API並等待請求

1
2
3
4
5
FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True or False to suppress this warning.
warnings.warn(FSADeprecationWarning(
* Debugger is active!
* Debugger PIN: 124-333-105
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

打開瀏覽器並進到 http://127.0.0.1:5000/
就會看到輸出的字串了!

待續

文章先寫到這吧不想讓這篇變太長
串接資料庫的部分就留到下一篇囉
到時也會把 API 的 POST, DELETE 方法給做出來

前言

最近把日期選擇器開發到一個段落了
差不多要發布了吧…

等等! 我的開發紀錄才寫了兩篇欸
後面還有很多內容沒寫
而且其實唯一寫的那兩篇規劃的東西大部分都改了…

好啦我之後補!!!
現在誰也不能阻止我發布套件!!!

NPM 是什麼?

NPM, Node Package Manager
是 NodeJS 專屬的 套件管理工具

就像 Python 有 pip,Ruby 有 gem 一樣
裡面放著來自世界各地工程師提供的套件
讓你可以不用從頭開始打造,就能使用許多功能

npm command line tool 會在你安裝 NodeJS 時一起被安裝

今天這篇便是要來介紹如何在 npm 上發布自己的套件
那我當然就以 react native 為例囉!

發布步驟

1. 建立專案資料夾

1
2
mkdir react-native-neat-date-picker
cd react-native-neat-date-picker

2. 連結 github

到 github 上建立一個新的 repository 叫 react-native-neat-date-picker
並將它連結到你的專案資料夾

1
2
3
4
5
6
7
echo "# test" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/roto93/react-native-neat-date-picker.git
git push -u origin main

3. 建立專案

執行 npm init
接下來他會問你一系列問題
以下是我的輸入值

1
2
3
4
5
6
7
8
9
package name: (react-native-date-picker) react-native-neat-date-picker
version: (1.0.0)
description: An easy-to-use date picker for React Native
entry point: (index.js)
test command:
git repository: (https://github.com/roto93/react-native-date-picker.git)
keywords: react-native, date, datePicker, date-picker, date picker, react native
author: roto93
license: (ISC) MIT
  • package name: 套件的名稱。
  • version: 版本,通常從 1.0.0 開始。
    之後每次你 publish 套件到 npm 時都必須更新版本,如果沒更新 npm 不會讓你發布。
  • description: 套件描述。可以在這裡描述套件的主要功能。
  • entry point: 套件的程式進入點。
    一般來說不會更動,維持index.js就好。
    雖然自訂進入點也是可以,但會不利於其他人 contribute
  • test command: 執行測試的指令,我目前沒用到所以沒深入研究。
  • git repository: 原始碼來源。
    之所以會在 npm init 之前就先建立 github repo 就是為了讓這裡能自動設定。
    我個人是認為 github 要打從一開始就設定好比較不會有問題
  • keywords: 關鍵字。
    意思是其他人可以藉由查詢什麼關鍵字來找到你的套件,越多越相關越好。
  • author: 作者。
    通常就放自己的 github 帳號,或名字
  • license: 認證。
    open source 的認證百百種,通常最簡單的就選 ISC 或 MIT。
    他們的意思都差不多是:「嘿 自己拿去用啦 你可以自由修改 但不要哪天反過來說是我抄你的ㄛ」

4. 建立套件進入點

剛剛有提到 index.js 是套件的進入點,意思是你必須讓你的套件要提供的功能從 index.js 中 export 出去。
你可以選擇直接把套件主程式寫在 index.js 裡
或者是你也可以寫在其他檔案中,import 進 index.js 裡,再 export
我的作法是後者,因為一開始開發時我就直接把主元件寫在 components 資料夾裡了,
如果現在又改變結構的話還要處理一些 import 的路徑問題
但我懶

1
2
3
// index.js
import DatePicker from './src/components/NeatDatePicker'
export default DatePicker

5. 設定 Babel

Babel 簡單來說是一個語法轉換器。
以網頁為例,就是讓瀏覽器可以使用 JS 的新語法

很幸運地,有現成的 preset 可以使用

1
npm install metro-react-native-babel-preset --save-dev

接著新增一個 .babelrc 檔案
裡面放:

1
2
3
{
"presets": ["module:metro-react-native-babel-preset"]
}

這部分就 ok 了

6. 建立 .gitignore 和 .npmignore

這兩份檔案會影響到當你上傳套件或 push 到 github 時,要忽略那些檔案
這邊提供簡單的 template
可以再視情況做增減

.gitignore

1
2
3
4
5
6
7
8
9
10
11
# Logs
*.log
npm-debug.log

# Runtime data
tmp
build
dist

# Dependency directory
node_modules

.npmignore

1
2
3
4
5
6
7
8
9
10
11
12
# Logs
*.log
npm-debug.log

# Dependency directory
node_modules

# Runtime data
tmp

# Examples (If applicable to your project)
examples

7. 本地測試

在發布之前,比較好的做法是先進行本地安裝測試看看
如果先發布,後來卻發現有嚴重問題的話就會修改得很匆忙
因為很可能已經有人下載來用了
然後他們就會覺得這套件怎麼這麼爛XD
與其如此不如在發布前先確保沒有什麼大問題

雖然這麼說
但我其實這步驟沒有成功
但我還是把流程放上來辣

首先在你即將發布套件的專案中執行
npm link
這行命令會告訴 npm
這個資料夾的專案是一個可安裝的套件喔

接著你進到本地的任何一個 app 專案中
執行 npm link react-native-neat-date-picker
便會進行本地安裝

如果以上步驟遇到問題
也可以選擇以路徑安裝
如: npm install {PATH_TO_PACKAGE}

這個做法的先天缺陷是一旦你對套件本身有做任何修改
你必須重新安裝一次,才能更新

不過很可惜上述兩個方法我都沒成功,
link 沒報錯,install 也沒 error
但 import 時就告訴我找不到 module
試了網路上很多方法都不行,所以我乾脆先跳過
直接發布試試看
結果可以 run ! 到底是怎樣 !!!

8. 發布

終於進到發布的環節了
首先我們登入 npm (你要先去註冊)

1
npm login

接著

1
npm publish

完成! 現在任何人都可以上去下載你提供的套件了
國家…不
我是說全世界都會感謝你的:)))

結語

上傳我的第一個 npm 套件實在是很興奮
可是也隱約有股壓力,因為不知道大家會不會覺得東西很爛
而且因為我發布的時候連 README 都很不完整,
也就是說前期下載的人可能完全不知道怎麼用
所以發布後到寫文的現在經過的這兩天
我便盡力把 README 補充到至少知道用法的地步
最後
希望世界上有人會喜歡我的套件
哈哈哈哈哈

什麼是 reaimated ?

reanimated 完整名稱是 react-native-reanimated
是一個專門用來做 react native 動畫的套件
在我寫這篇文的現在,最新穩定版本是 v2.2.0

前言

在過去 v1 時期,要學習還蠻不容易的
想當初我就是先接觸 v1,那時候我對 rn 和 js 的基礎都還不熟
看網路上的教學時一下看到用 Animated.Value,一下有人用 useRef.current
語法有點不一樣我就不行了,更不用說當時大多數人都還在用 class component
所以學得蠻挫折的,我到現在還不知道要怎麼用 v1 實作動畫

2020 年中推出的 v2 給了我一絲希望
他提供幾個方便的 hook,簡單幾行就可以實現動畫
太開心了
多虧了它我才能在菜鳥時期學會做一些不太複雜的動畫
(不過基礎還是應該要先會啦XD)

v2 版本也被很多 youtuber 推薦
其最大的優點在於能將動畫統一放到 UI thread 上執行
甚至提供一些 method 讓我們能操作 JS/UI thread
於是動畫就能變得非常流暢
我真的覺得一個 app 好不好用,順暢度真的佔了很大一部份

安裝

今天會想整理這篇是因為當初在安裝時耗了很多工夫
除了一直來來回回安裝
也很怕不小心把專案毀了回不去

這是因為我沒注意到不同 expo-cli 版本可以使用的 reanimated 版本是不一樣的
安裝前必須先確認好才行
不過現在已經沒有這個問題了

  1. npm 安裝
1
npm install react-native-reanimated
  1. 打開babel.config.js
1
2
3
4
5
6
7
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: ['react-native-reanimated/plugin'], // <-- 加上這行
};
};
  1. 重新啟動專案並清除 cache

再次啟動時不要執行npm start,而是

1
expo start -c

這步非常重要,當初不知道這個步驟的我浪費非常多時間
偏偏 doc 裡面也沒講 QQ

至此,只要安裝版本正確、有加 plugin、有清除 cache
就可以順跑ㄌ…我是說使用 reanimated 了

初探 worklet

worklet 是 v2 新發布的功能,介紹功能之前先讓大家看看它的用法

1
2
3
4
5
6
7
8
9
10

const doSomething = (input)=>{
// do something
}

const doSomethingWorklet = (input)=>{
'worklet'
// do something
}

跟一般的 function 幾乎沒差異
就只是在閉包裡頭第一行多寫一句'worklet'而已
當一個 fuction 被定義成 worklet,它就「能」被交由 UI thread 執行
至於什麼是 UI thread 嘛…

就定義而言,它是從原本的 javascript thread 中分離出來的一部份
你可以把 UI thread 看成是 JS 因忙不過來而請來的助理
顧名思義,UI thread 主要是用來處理畫面渲染的工作的

而 reanimated 引入 worklet 這個新用法正是為了讓動畫從 app 的運算中獨立出來
不要讓動畫被其他事情影響卡住,能夠順順跑

另外有發現我前面強調「能」由 UI thread 執行嗎?
這是因為如果真的要在 UI thread 執行,必須用runOnUI這個函式才行
如下:

1
2
3
<Button onPress={()=>{
runOnUI(doSomethingWorklet)(input) // doSomethingWorklet 將會在 UI thread 執行
}}>

那如果情況反過來,我想在 worklet 中執行 JS thread 怎麼辦?
方法很類似,只要用runOnJS就行了

1
2
3
4
const doSomethingWorklet = () => {
'worklet'
runOnJS(doSomething)(input) // doSomething 將會在 JS thread 執行
}

值得一提的是這個runOnJS會蠻常碰到的
例如我在做匯率 APP 的時候有些按鈕同時兼顧動畫跟 setState
state 的變動就必須用runOnJS來執行了

結語

今天的超入門介紹就到這邊
雖然還沒講到能實作動畫的階段
但我覺得快速確實地安裝好套件
並搞清楚workletrunOnUIrunOnJS的用法原理還是很重要的

下一篇介紹 reanimated 的文就會來說說useSharedValueuseAnimatedStyle怎麼使用!