今天我們來讓 App 具備基本的 UI 以及新增、輸出記錄的相關功能。
筆者預期會有兩個區塊,每個區塊會有一個按鈕,按下去以後會觸發特定的動作。
這兩個按鈕分別是:
讓我們進到 App.js
中,將預設的 Scrollview
段落改為:
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={backgroundStyle}>
<View
style={{
backgroundColor: isDarkMode
? Colors.black
: Colors.white,
}}>
<Section title={'Annoyance Notification'} />
<Section title="記錄關門聲">
<Button title="點我" onPress={storeTimeRecord} />
</Section>
<Section title="輸出檔案">
<Button title="點我" onPress={getAllStoredRecords} />
</Section>
<Section title="清除所有儲存資料(開發用)">
<Button title="確定點我?" onPress={clearAll} />
</Section>
</View>
</ScrollView>
筆者為了後續資料處理邏輯的開發方便,暫時增加第三個按鈕,以清除所有本地資料
,待開發完成後再刪除此區塊。
完成後我們 UI 會長這樣:
筆者原先想要使用 SQLite
,但在調查的過程中發現 React Native 有自身獨特的 API:AsyncStorage
,便想趁此次機會試試看。
但打開官方的文件一看,AsyncStorage 的 API 已經 Deprecated了。於是我們進一步調查,找到 stackoverflow 的這篇,推測我們安裝這個套件可以達到類似的效果:@react-native-async-storage/async-storage
。
讓我們安裝套件後在 App.js
中 import 進來:
import AsyncStorage from '@react-native-async-storage/async-storage';
上述三個按鈕分別對應的 function,讓我們依次建立:
const storeTimeRecord = async () => {
const now = new Date();
// Monday: 1
const weekday = now.getDay();
const preciseHour = now.getHours();
const preciseMin = now.getMinutes();
const year = now.getFullYear();
const month = now.getUTCMonth() + 1;
const formattedMonth = month < 10 ? `0${month}` : month;
const date = now.getDate();
// eg. 20221010
const key = `${year}${formattedMonth}${date}`;
const value = {
preciseTime: `${preciseHour}:${preciseMin}`,
weekday,
};
// TODO: implementation of deviation field
try {
await AsyncStorage.setItem(key, JSON.stringify(value));
Alert.alert('record stored');
} catch (e) {
console.error(e);
}
};
因為 value 是 object 的關係,我們必須先透過 JSON.stringify
轉換成字串後才能順利存入。
此次先處理具體時間+日期+星期幾
的欄位,待預測的時間的通知建立後,此段會再加入新的欄位處理方式。
const getAllStoredRecords = async () => {
let keys = [];
try {
keys = await AsyncStorage.getAllKeys();
} catch (e) {
console.log(e);
}
const records = await Promise.all(
keys.map(async key => {
const value = await getData(key);
return {key, value};
}),
);
const message = JSON.stringify(records);
// TODO: export, not just display
Alert.alert(message);
};
這邊的做法是取得目前本地 AsyncStorage 儲存的所有 key
,然後再透過 getData
取得所有 key 對應的 value。
因為時間關係,筆者今天只處理到將所有儲存的資料印出來。
const clearAll = async () => {
try {
await AsyncStorage.clear();
} catch (e) {
console.log(e);
}
Alert.alert('All data cleared');
};
如果出現錯誤以下錯誤:
Error: Requiring module "node_modules/@react-native-async-storage/async-storage/src/index.ts", which threw an exception: Error: [@RNC/AsyncStorage]: NativeModule: AsyncStorage is null.
記得要重新 build:
npx react-native start
再重新啟動虛擬機並且執行:
npx react-native run-android
讓我們看一下執行成果:
儲存資料:
讀取資料:
今天收工!