Airtable

Airtable with REST

2020/11/06(更新內容)
2020/12/02 (補充內容)

Airtable

Airtable是個雲端服務,提供類似試算表的資料庫,可以利用airtable提供的javascript library或者利用REST存取資料。在這邊先介紹如何透過REST存取資料。

** 注意 ** Airtable API支援有限,如果要開發專題,不推薦使用Airtable。

Airtable.pptx
  • 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

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"

當資料越來越多的時候,怎麼處理分頁呢?

參考資料

  • 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;