Airtable
Airtable with REST
2020/11/06(更新內容)
2020/12/02 (補充內容)
Airtable
Airtable是個雲端服務,提供類似試算表的資料庫,可以利用airtable提供的javascript library或者利用REST存取資料。在這邊先介紹如何透過REST存取資料。
** 注意 ** Airtable API支援有限,如果要開發專題,不推薦使用Airtable。
![](https://www.google.com/images/icons/product/drive-32.png)
Airtable
新增base
設定你們的資料表
新增欄位
View
API
REST
先參考前面的範例(ProductList.js),先把UI的部分改成react native的FlatList,另外,新增一個:
/src/person/PersonList.js
import React, {useState, useEffect} from 'react';
import {FlatList, View, Text} from 'react-native';
import {Icon, Fab} from 'native-base';
import styles from '../styles';
export default function PersonList() {
const renderItem = ({ item, index }) => (
<View style={styles.item}>
<Text>{index}</Text>
<Text style={styles.title}>{item.Name}</Text>
<Text>{item.City},</Text>
<Text>{item.Age}</Text>
</View>
);
const [persons, setPersons] = useState([
{Name: "Ben", City:"Taipei", Age:16},
{Name: "Cathy", City:"Taipei", Age:26}
]);
return (
<View style={styles.container}>
<FlatList
data={persons}
renderItem = {renderItem}
keyExtractor={(item, index) => ""+index}
>
</FlatList>
</View>
);
}
把personList放到App.js裡
import React, {useState} from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
//import { createStackNavigator } from '@react-navigation/stack';
import PersonList from './src/person/PersonList';
import ProductList from './src/product/ProductList';
import Click from './src/Click';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}
//const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
function App() {
const [count, setCount] = useState(10);
let countString = "count in App:"+count;
function updateCount(newCount){
setCount(newCount);
}
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Person" component={PersonList} />
<Tab.Screen name="Product" component={ProductList} />
<Tab.Screen name="Click" component={Click} initialParams={{ count: 10 }}/>
</Tab.Navigator>
</NavigationContainer>
);
}
export default App;
GET
我們可以利用javascript內建的fetch來呼叫RESTful web services,也可以利用Axios,採用Axios的好處是,Axios會自動處理json的內容 (詳參: Fetch vs. Axios.js for making http requests)。
簡單的解釋如何使用Axios
Step 1 — Adding Axios to the Project
Step 2 — Making a GET Request
Step 3 — Making a POST Request
Step 4 — Making a DELETE Request
Step 5 — Using a Base Instance in Axios
Step 6 — Using async and await
What is Axios and how to use it with React
Axios basic APIs
Making it work with React
Using async/await
Configuring Axios
首先,先安裝axios
expo install axios
Airtable API,其中「appLNbQOB0WL1ZeDD」是Base id,「Table%201」是table名稱,原本table名稱是「Table 1」名稱中間的空白,用%20取代(URI Encode),接下來利用Query進行參數設定,maxRecords是設定回傳的資料最高筆數,view是設定view的名稱,「Grid view」就變成「Grid%20view」。-H是http的header。
curl "https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201?maxRecords=3&view=Grid%20view" \
-H "Authorization: Bearer YOUR_API_KEY"
連接airtable,是透過Bearer token,所以,要設定header,並將airtable的API中的key取代程式中的XXXXXXXXXXXXXXXXX。
const axios_config = {
headers: {'Authorization': 'Bearer XXXXXXXXXXXXXXXXX'}};
接下來要將「appLNbQOB0WL1ZeDD」取代為你的Base id,「Table%201」,取代為你的table名稱,如果table名稱有空白,就要用%20取代(URI Encode),如果改了view的名稱,也要記得修改「Grid%20view」。
const url="https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201?maxRecords=30&view=Grid%20view";
呼叫get。
const result = await axios.get(url,axios_config);
取得的資料格式:
"data": Object {
"records": Array [
Object {
"createdTime": "2019-03-08T06:18:45.000Z",
"fields": Object {
"Age": 20,
"City": "台北市",
"Name": "Ben Wu",
"photoId": "14_ERjayewC7HF9uFw5BIRB0ng3TAA97M",
},
"id": "rec6USTCW7WQS1D4H",
},
Object {
"createdTime": "2019-03-08T06:18:45.000Z",
"fields": Object {
"Age": 6,
"Attended": true,
"City": "新北市",
"Name": "Ana",
"Preferences": Array [
"Book",
"Magazine",
],
},
"id": "recM3qifn7g8hlLhy",
},
設定state,預設為空陣列
const [persons, setPersons] = useState([]);
這邊使用到javascript的語法async await (詳參: Javascript 裡Asynchronous的說明)
async function fetchData () {
const result = await axios.get(url,axios_config);
}
因為資料會包在data的records裡,所以,取得資料時,要用data.records,取得的資料就放到Persons裡。
async function fetchData () {
const result = await axios.get(url,axios_config);
//console.log(result);
setPersons(result.data.records);
}
useEffect(() => {
fetchData();
},[]);
因為資料內容又包在fields中,取得時要加fields
const renderItem = ({ item, index }) => (
<View style={styles.item}>
<Text>{index}</Text>
<Text style={styles.title}>{item.fields.Name}</Text>
<Text>{item.fields.City},</Text>
<Text>{item.fields.Age}</Text>
</View>
);
FlatList中定義data及renderItem
<FlatList
data={persons}
renderItem = {renderItem}
keyExtractor={(item, index) => ""+index}
>
</FlatList>
程式碼 (記得要將airtable的url改成你們的url,並使用API中的key取代程式中的XXXXXXXXXXXXXXXXX):
/src/person/PersonList.js
import React, {useState, useEffect} from 'react';
import {FlatList, View, Text} from 'react-native';
import {Icon, Fab} from 'native-base';
import axios from 'axios';
//import ProductAdd from './ProductAdd';
import styles from '../styles';
export default function PersonList() {
const axios_config = { headers: {'Authorization': 'Bearer XXXXXXXXXXXXXXXXX'} };
const url="https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201?maxRecords=30&view=Grid%20view";
const [persons, setPersons] = useState([]);
const renderItem = ({ item, index }) => (
<View style={styles.item}>
<Text>{index}</Text>
<Text style={styles.title}>{item.fields.Name}</Text>
<Text>{item.fields.City},</Text>
<Text>{item.fields.Age}</Text>
</View>
);
async function fetchData () {
const result = await axios.get(url,axios_config);
//console.log(result);
setPersons(result.data.records);
}
useEffect(() => {
fetchData();
},[]);
return (
<View style={styles.container}>
<FlatList
data={persons}
renderItem = {renderItem}
keyExtractor={(item, index) => ""+index}
>
</FlatList>
</View>
);
}
ActivityIndicator
探索一下,當我們讀取資料時,會稍微停頓一下,可以利用ActivityIndicator 或類似的元件,讓使用者知道資料準備中,可以利用animating所指定的變數(如:isLoading)來打開或關掉,處理的方式跟modal很像。大家試試看囉!
<ActivityIndicator color="red" size="large" animating={isLoading} />
POST
先依據ProductAdd,修改一下內容。
/src/person/PersonAdd.js
import React, {useState} from 'react';
import { Button , TextInput, Modal } from 'react-native';
export default function PersonAdd(props) {
const [name, setName] = useState("");
const [city, setCity] = useState("");
const [age, setAge] = useState(0);
function update(){
props.update();
}
return (
<Modal visible={props.modalVisible}>
<TextInput placeholder="姓名" value={name} onChangeText={text=>setName(text)}/>
<TextInput placeholder="城市" value={city} onChangeText={text=>setCity(text)}/>
<TextInput placeholder="年齡" value={age} onChangeText={text=>setAge(text)}/>
<Button onPress={update} title="新增"/>
</Modal>
);
}
把PersonAdd加進PersonList,也參考ProductList,修改一下介面 (如:FAB)。/src/person/PersonList.js
import React, {useState, useEffect} from 'react';
import {FlatList, View, Text} from 'react-native';
import {Icon, Fab} from 'native-base';
import axios from 'axios';
import PersonAdd from './PersonAdd';
import styles from '../styles';
export default function PersonList() {
const axios_config = {
headers: {'Authorization': 'Bearer XXXXXXXXXXXXXXXXX'}
};
const url="https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201?maxRecords=30&view=Grid%20view";
const [persons, setPersons] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
async function fetchData () {
const result = await axios.get(url,axios_config);
//console.log(result);
setPersons(result.data.records);
}
useEffect(() => {
fetchData();
},[]);
function update(){
setModalVisible(false);
}
const renderItem = ({ item, index }) => (
<View style={styles.item}>
<Text>{index}</Text>
<Text style={styles.title}>{item.fields.Name}</Text>
<Text>{item.fields.City},</Text>
<Text>{item.fields.Age}</Text>
</View>
);
return (
<View style={styles.container}>
<FlatList
data={persons}
renderItem = {renderItem}
keyExtractor={(item, index) => ""+index}
>
</FlatList>
<Fab onPress={()=>setModalVisible(true)}>
<Icon ios='ios-add' android="md-add"/>
</Fab>
<PersonAdd modalVisible = {modalVisible} update={update}/>
</View>
);
}
Airtable API裡,新增資料要使用POST,POST跟GET不一樣的是,要傳送新增的內容到airtable。
curl -v -X POST https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"fields": {
"Name": "Ben Wu",
"Age": 20,
"City": "台北市",
"photoId": "14_ERjayewC7HF9uFw5BIRB0ng3TAA97M"
}
}'
POST也會有回傳值,只是,回傳的內容是新增的內容,其中,會回傳新增內容的id。
EXAMPLE RESPONSE
{
"records": [
{
"id": "rec6USTCW7WQS1D4H",
"fields": {
"City": "台北市",
"Age": 20,
"Name": "Ben Wu"
},
"createdTime": "2019-03-08T06:18:45.000Z"
},
首先,要使用post,除此之外,還必須包括要新增的資料(如:newPerson)
const result = await axios.post(url,newPerson, axios_config);
資料要依照API的期待去包裝,欄位要包在fields裡,欄位名稱及資料型態要跟資料表裡的名稱一致。
const newPerson={
fields:{
Name:name,
City:city,
Age:parseInt(age)
}
}
另外,headers裡要設定Content-Type。
const axios_config = {
headers: {
'Authorization': 'Bearer XXXXXXXXXXXXXXXXX',
'Content-Type': 'application/json'}
};
上次老師並沒有介紹錯誤處理的方式,利用async/await可以利用try/catch處理錯誤,萬一有錯誤,會利用console.log印出錯誤碼,錯誤碼的說明請參閱Airtable的API說明。
try {
const result = await axios.post(url,newPerson, axios_config);
console.log(result);
//setPersons(result.data.records);
props.update();
}
catch (e){
console.log("error:"+e);
}
完整的程式碼:
/src/person/PersonAdd.js
import React, {useState} from 'react';
import { Button , TextInput, Modal } from 'react-native';
import axios from 'axios';
export default function PersonAdd(props) {
const [name, setName] = useState("");
const [city, setCity] = useState("");
const [age, setAge] = useState("0");
const axios_config = {
headers: {
'Authorization': 'Bearer XXXXXXXXXXXXXXXXX',
'Content-Type': 'application/json'}
};
const url="https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201";
async function sendData () {
const newPerson={
fields:{
Name:name,
City:city,
Age:parseInt(age)
}
}
//console.log(newPerson);
try {
const result = await axios.post(url,newPerson, axios_config);
console.log(result);
//setPersons(result.data.records);
props.update();
}
catch (e){
console.log("error:"+e);
}
}
function update(){
sendData();
}
return (
<Modal visible={props.modalVisible}>
<TextInput placeholder="姓名" value={name} onChangeText={text=>setName(text)}/>
<TextInput placeholder="城市" value={city} onChangeText={text=>setCity(text)}/>
<TextInput placeholder="年齡" value={age} onChangeText={text=>setAge(text)}/>
<Button onPress={update} title="新增"/>
</Modal>
);
}
useEffect
這時候會發現雖然內容出現在airtable上,可是手機上看不到,這是因為我們的useEffect的第二個參數是空陣列,useEffect只會執行一次,所以,useEffect不會更新。如果沒有第二個參數的話,會監控所有的state,因為persons的內容是被REST服務更新,會造成useEffect一直在執行,所以,要設定為監控特定變數,因為,每次新增都會更動modalVisible,所以,我們就監控這個變數:
useEffect(() => {
},[modalVisible]);
/src/person/PersonList.js
import React, {useState, useEffect} from 'react';
import {FlatList, View, Text} from 'react-native';
import {Icon, Fab} from 'native-base';
import axios from 'axios';
import PersonAdd from './PersonAdd';
import styles from '../styles';
export default function PersonList() {
const [persons, setPersons] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const axios_config = {
headers: {'Authorization': 'Bearer XXXXXXXXXXXXXXXXX'}
};
const url="https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201?maxRecords=30&view=Grid%20view";
async function fetchData () {
const result = await axios.get(url,axios_config);
//console.log(result);
setPersons(result.data.records);
}
useEffect(() => {
fetchData();
},[modalVisible]);
function update(){
setModalVisible(false);
}
const renderItem = ({ item, index }) => (
<View style={styles.item}>
<Text>{index}</Text>
<Text style={styles.title}>{item.fields.Name}</Text>
<Text>{item.fields.City},</Text>
<Text>{item.fields.Age}</Text>
</View>
);
return (
<View style={styles.container}>
<FlatList
data={persons}
renderItem = {renderItem}
keyExtractor={(item, index) => ""+index}
>
</FlatList>
<Fab onPress={()=>setModalVisible(true)}>
<Icon ios='ios-add' android="md-add"/>
</Fab>
<PersonAdd modalVisible = {modalVisible} update={update}/>
</View>
);
}
比較一下PersonList及PersonAdd,就會發現,有些變數是共用的,可以將axios_config以及url的部分另外定義,再import進來。
先將共用的部分,放到 /src/person/config.js
export const axios_config = {
headers: {
'Authorization': 'Bearer XXXXXXXXXXXXXXXXX',
'Content-Type': 'application/json'}
};
export const url="https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201";
/src/person/PersonList.js
import React, {useState, useEffect} from 'react';
import {FlatList, View, Text} from 'react-native';
import {Icon, Fab} from 'native-base';
import axios from 'axios';
import PersonAdd from './PersonAdd';
import styles from '../styles';
import {axios_config, url} from './config';
export default function PersonList() {
const get_url=url+"?maxRecords=50&view=Grid%20view";
const [persons, setPersons] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
async function fetchData () {
const result = await axios.get(get_url,axios_config);
//console.log(result);
setPersons(result.data.records);
}
useEffect(() => {
fetchData();
},[modalVisible]);
function update(){
setModalVisible(false);
}
const renderItem = ({ item, index }) => (
<View style={styles.item}>
<Text>{index}</Text>
<Text style={styles.title}>{item.fields.Name}</Text>
<Text>{item.fields.City},</Text>
<Text>{item.fields.Age}</Text>
</View>
);
return (
<View style={styles.container}>
<FlatList
data={persons}
renderItem = {renderItem}
keyExtractor={(item, index) => ""+index}
>
</FlatList>
<Fab onPress={()=>setModalVisible(true)}>
<Icon ios='ios-add' android="md-add"/>
</Fab>
<PersonAdd modalVisible = {modalVisible} update={update}/>
</View>
);
}
/src/person/PersonAdd.js
import React, {useState} from 'react';
import { Button , TextInput, Modal } from 'react-native';
import axios from 'axios';import {axios_config, url} from './config';
export default function PersonAdd(props) {
const [name, setName] = useState("");
const [city, setCity] = useState("");
const [age, setAge] = useState("0");
async function sendData () {
const newPerson={
fields:{
Name:name,
City:city,
Age:parseInt(age)
}
}
//console.log(newPerson);
try {
const result = await axios.post(url,newPerson, axios_config);
console.log(result);
//setPersons(result.data.records);
props.update();
}
catch (e){
console.log("error:"+e);
}
}
function update(){
sendData();
}
return (
<Modal visible={props.modalVisible}>
<TextInput placeholder="姓名" value={name} onChangeText={text=>setName(text)}/>
<TextInput placeholder="城市" value={city} onChangeText={text=>setCity(text)}/>
<TextInput placeholder="年齡" value={age} onChangeText={text=>setAge(text)}/>
<Button onPress={update} title="新增"/>
</Modal>
);
}
Put/Patch
如何修改一筆資料呢?
將API跟POST比較一下,會發現除了將POST改為PATCH(或PUT)之外,因為要知道是要更新哪一筆資料,所以,需要id。
curl -v -X PATCH https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"records": [
{
"id": "rec6USTCW7WQS1D4H",
"fields": {
"Name": "Ben Wu",
"Age": 20,
"City": "台北市",
"photoId": "14_ERjayewC7HF9uFw5BIRB0ng3TAA97M"
}
},
{
"id": "recM3qifn7g8hlLhy",
"fields": {
"Name": "Ana",
"Attended": true,
"Preferences": [
"Book",
"Magazine"
],
"Age": 6,
"City": "新北市"
}
}
]
}'
在Functional Component 也說明TouchableOpacity的使用方法,這裡就先把這些部分先組合起來。也可以參考FlatList ,裡面有提到如何處理onPress,並且知道哪一筆被點選。
/src/person/PersonList.js
import React, {useState, useEffect} from 'react';
import {FlatList, View, Text, TouchableOpacity} from 'react-native';
import {Icon, Fab} from 'native-base';
import axios from 'axios';
import PersonAdd from './PersonAdd';
import styles from '../styles';
import {axios_config, url} from './config';
export default function PersonList() {
const get_url=url+"?maxRecords=50&view=Grid%20view";
const [persons, setPersons] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const [selectedId, setSelectedId] = useState(null);
useEffect(() => {
async function fetchData () {
const result = await axios.get(get_url,axios_config);
//console.log(result);
setPersons(result.data.records);
}
fetchData();
},[modalVisible]);
function update(){
setModalVisible(false);
}
const Item = ({ index, item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.item, style]}>
<Text>{index}</Text>
<Text style={styles.title}>{item.fields.Name}</Text>
<Text>{item.fields.City},</Text>
<Text>{item.fields.Age}</Text>
</TouchableOpacity>
);
const renderItem = ({ item, index }) => {
const backgroundColor =
item.id === selectedId ? "#f9c2ff" : styles.item.backgroundColor;
return (
<Item
index={index}
item={item}
onPress={() => setSelectedId(item.id)}
style={{ backgroundColor }}
/>
)
};
return (
<View style={styles.container}>
<FlatList
data={persons}
renderItem = {renderItem}
keyExtractor={(item, index) => ""+index}
>
</FlatList>
<Fab onPress={()=>setModalVisible(true)}>
<Icon ios='ios-add' android="md-add"/>
</Fab>
<PersonAdd modalVisible = {modalVisible} update={update}/>
</View>
);
}
接下來,我們可以試著將資料傳進PersonAdd.js。先複製PersonAdd.js改名為:PersonAddEdit.js
新增與修改有一些不同:
await axios.put(url,newPerson, axios_config)
因為要修改,所以,newPerson的內容裡要有id,另外,airtable接受同時修改多筆,所以,要放在陣列裡。
const newPerson =
{records:[{
id: id,
fields:{
Name:name,
City:city,
Age:parseInt(age)
}}]
}
比較複雜的是,要把點選的內容傳入PersonAddEdit。
<PersonAddEdit modalVisible = {modalVisible} person = {person} id={selectedId} hide={hide}/>
因為新增與修改的動作不太一樣,所以,呼叫的方式與處理的function也不一樣。新增的部分:
<Fab onPress={()=>add()}>
<Icon ios='ios-add' android="md-add"/>
</Fab>
修改的部分:
const renderItem = ({ item, index }) => {
const backgroundColor = item.id === selectedId ? "#f9c2ff" : styles.item.backgroundColor;
return (
<Item
index={index}
item={item}
onPress={() => update(item.id, index)}
style={{ backgroundColor }}
/>
)
};
add()裡面把selectedID設為空白,否則,會取到上次新增資料的id。
function add(){
setPerson({
Name:"",
City:"",
Age:0
});
setSelectedId("");
setModalVisible(true);
}
update()裡,根據選到的index,取陣列裡的對應資料,放到person裡,並且設定selectedId。
function update(id, index){
setPerson({
Name:persons[index].fields.Name,
City:persons[index].fields.City,
Age:persons[index].fields.Age
});
setSelectedId(id);
setModalVisible(true);
}
完整的/src/person/PersonAddEdit.js
import React, {useState, useEffect} from 'react';
import { Button , TextInput, Modal } from 'react-native';
import axios from 'axios';
import {axios_config, url} from './config';
export default function PersonAddEdit(props) {
const [name, setName] = useState("");
const [city, setCity] = useState("");
//transfer age to a string for TextInput
const [age, setAge] = useState("0");
useEffect(()=>{
setName(props.person.Name);
setCity(props.person.City);
setAge(""+props.person.Age);
},[props.id]);
function update(){
async function sendData () {
// if id exists, assign a newPerson with id
// else assign a newPerson without id
const newPerson = props.id
?{records:[{
id: props.id,
fields:{
Name:name,
City:city,
Age:parseInt(age)
}}]
}
:{fields:{
Name:name,
City:city,
Age:parseInt(age)
}}
try {
// if id exists, call put
// else call post
const result = props.id
?await axios.put(url,newPerson, axios_config)
:await axios.post(url,newPerson, axios_config);
props.hide();}
catch (e){
console.log("error:"+e);
}
}
sendData();
}
return (
<Modal visible={props.modalVisible}>
<TextInput placeholder="姓名" value={name} onChangeText={text=>setName(text)}/>
<TextInput placeholder="城市" value={city} onChangeText={text=>setCity(text)}/>
<TextInput placeholder="年齡" value={age} onChangeText={text=>setAge(text)}/>
<Button onPress={update} title="確定"/>
<Button onPress={props.hide} title="取消"/>
</Modal>
);
}
完整的/src/person/PersonList.js
import React, {useState, useEffect} from 'react';
import {FlatList, View, Text, TouchableOpacity} from 'react-native';
import {Icon, Fab} from 'native-base';
import axios from 'axios';
import PersonAddEdit from './PersonAddEdit';
import styles from '../styles';
import {axios_config, url} from './config';
export default function PersonList() {
const get_url=url+"?maxRecords=50&view=Grid%20view";
const [persons, setPersons] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const [selectedId, setSelectedId] = useState(null);
const [person, setPerson] = useState({
Name:"",
City:"",
Age:0}
);//temp variable for edit
useEffect(() => {
async function fetchData () {
const result = await axios.get(get_url,axios_config);
//console.log(result);
setPersons(result.data.records);
}
fetchData();
},[modalVisible]);
function hide(){
setSelectedId("");
setModalVisible(false);
}
function add(){
setPerson({
Name:"",
City:"",
Age:0
});
setSelectedId("");
setModalVisible(true);
}
function update(id, index){
setPerson({
Name:persons[index].fields.Name,
City:persons[index].fields.City,
Age:persons[index].fields.Age
});
setSelectedId(id);
setModalVisible(true);
}
const Item = ({ index, item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.item, style]}>
<Text>{index}</Text>
<Text style={styles.title}>{item.fields.Name}</Text>
<Text>{item.fields.City},</Text>
<Text>{item.fields.Age}</Text>
</TouchableOpacity>
);
const renderItem = ({ item, index }) => {
const backgroundColor = item.id === selectedId ? "#f9c2ff" : styles.item.backgroundColor;
return (
<Item
index={index}
item={item}
onPress={() => update(item.id, index)}
style={{ backgroundColor }}
/>
)
};
return (
<View style={styles.container}>
<FlatList
data={persons}
renderItem = {renderItem}
keyExtractor={(item, index) => ""+index}
>
</FlatList>
<Fab onPress={()=>add()}>
<Icon ios='ios-add' android="md-add"/>
</Fab>
<PersonAddEdit modalVisible = {modalVisible} person = {person} id={selectedId} hide={hide}/>
</View>
);
}
思考一下,接下來,要如何刪除(DELETE)資料? 有兩種方式,第一種方式可以刪除多筆資料:
curl -v -X DELETE https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201 \
-H "Authorization: Bearer YOUR_API_KEY" \
-G \
--data-urlencode 'records[]=rec6USTCW7WQS1D4H' \
--data-urlencode 'records[]=recM3qifn7g8hlLhy'
第二種方式是在URL後面直接加上要刪除資料的record id,比較簡單,但是,一次只能刪除一筆:
curl -v -X DELETE https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/Table%201/rec6USTCW7WQS1D4H \
-H "Authorization: Bearer YOUR_API_KEY"
當資料越來越多的時候,怎麼處理分頁呢?
How to add pagination to a React-Native flatlist
利用onEndReachedThreshold及onEndReached
React Native FlatList Pagination to Load More Data dynamically – Infinite List
利用button
參考資料
Airtable
在javascript裡,其實直接寫空白或特殊符號是可以的,因為javascript會自動進行encode。另外,如果要加篩選條件(如:City的內容是新北市),是可以利用filterByFormula。(詳參: 20 different ways to GET and filter data from Airtable)
const paramter = "Table 1?maxRecords=30&view=Grid view";
const formula = "&filterByFormula=({City}='新北市')";
const url="https://api.airtable.com/v0/appLNbQOB0WL1ZeDD/"+paramter+formula;
React
axios
Fetch
Airtable API
whatwg-fetch
CRUD
React Native Insert Update Display Delete CRUD Operations MySQL DB
資料有點舊,例如ListView已經被deprecated,要改用FlatList或SectionList