NCMBのReact Native SDKを使ってTodoアプリを作る（その3：Todoデータの更新と削除）

NCMBでは公式SDKの他、コミュニティSDKとして各種言語、フレームワーク向けにSDKを提供しています。今回はReact Native SDKを使ったTodoアプリ開発を解説します。

前回はTodoデータの登録と、一覧表示を解説しました。今回はTodoデータの更新と削除について解説します。

## コードについて

今回のコードは[NCMBMania/Expo-Todo-App: React Native SDKで作ったTodoアプリです](https://github.com/NCMBMania/Expo-Todo-App)にアップロードしてあります。また、Expo Snackでも使用できます。

[NCMB-Expo-Todo-App - Snack](https://snack.expo.dev/@goofmint/1706f4)

## 更新について

データの更新は2種類あります。

- チェックボックスを付けて、Todoデータを終了にする
- Todoの内容を変更する

### チェックボックスを付けて、Todoデータを終了にする

![FireShot Capture 097 - タスクの編集 - localhost 20211011161344 - 097.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/e82b7964-60a3-8037-b8c6-9b1a478b49e7.jpeg)


チェックボックスはTodoItem.jsにあります。

```js
// リスト（各行）の表示処理
return (
  <List.Item
    title={item.get('body')}
    // リストをタップしたら、編集画面に遷移する
    onPress={() => navigation.push('Detail', { index, item, updated })}
    // タスクの完了状態を見てチェックボックスを変更
    left={props => <Checkbox
      status={item.get('checked') ? 'checked' : 'unchecked'}
      // チェックボックスをタップしたら、完了状態を反転
      onPress={() => checked({index, item})}
      />
    }
    // > を表示
    right={props => <List.Icon
        icon="chevron-right"        
      />
    }
  />
)
```

CheckboxのonPressにて、checked関数を実行します。

```js
// タスクをチェックした際に呼ばれるアクション
const checked = ({index, item }) => {
  // データを更新（フラグを反転）
  item.set('checked', !item.get('checked'));
  // 保存
  item.save();
  updated({index, item});
};
```

updated関数は、Home.jsから送られてきている関数で、バナーを使ってタスクの更新を通知します。

```js
// タスクを更新した後に呼ばれるアクション
const updated = ({ item, index }) => {
  ary[index] = item;  // 配列の更新
  setArray([...ary]); // 配列を更新
  // バナーでメッセージ表示
  setMessage('タスクを更新しました');
};
```

### Todoの内容を変更する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/92b6f00d-b0a1-8015-a139-05e2841047b9.png)


Todoの内容を変更するのは、EditScreenになります。まず一覧の時点でTodoを選択すると、EditScreenに遷移します。List.ItemのonPressイベントになります。

```js
// リスト（各行）の表示処理
return (
  <List.Item
    title={item.get('body')}
    // リストをタップしたら、編集画面に遷移する
    onPress={() => navigation.push('Detail', { index, item, updated })}
    // タスクの完了状態を見てチェックボックスを変更
    left={props => <Checkbox
      status={item.get('checked') ? 'checked' : 'unchecked'}
      // チェックボックスをタップしたら、完了状態を反転
      onPress={() => checked({index, item})}
      />
    }
    // > を表示
    right={props => <List.Icon
        icon="chevron-right"        
      />
    }
  />
)
```

EditScreenでは、まず入力内容を取得します。

```js
import React, { useState } from 'react';
import { View, StyleSheet } from 'react-native';
import { TextInput } from 'react-native-paper';

export default function EditTodo({ route, navigation }) {
  const {index, item, updated} = route.params;
  const [text, setText] = useState(item.get('body'));
}
```

そして表示します。

```js
return (
  <View style={styles.container}>
    <TextInput
      label="タスク"
      mode="flat"
      dense="true"
      value={text}
      style={styles.textInput}
      onChangeText={(text) => setText(text)}
      onKeyPress={keyPress}
    />
  </View>
);
```

タスクの更新は、新規登録の際と同じく、入力確定のタイミングで処理を行います。新しいTodoの内容をitem（NCMBObject）に適用して保存します。その後、バナーでの更新通知を行い、 `navigation.goBack()` を使って前の画面（一覧画面）へ戻ります。

```js
// エンターキーが押された際のイベントです
const keyPress = async (e) => {
  if(e.which === 13){
    try {
      // タスクを更新します
      await item
        .set('body', text)
        .save();
      updated({index, item });
      navigation.goBack();
    } catch (e) {
      console.log(e);   
    }
  }
};
```

## 削除について

![FireShot Capture 097 - タスクの編集 - localhost 20211011161344 - 097.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/f4bbeb4f-e3b7-a476-edc8-a8eec587fef7.jpeg)


Todoの削除はHome.jsにて行います。チェックが付いたタスクを対象に、データを削除します。まず1つでもチェックが付いているタスクがあるかどうかを判定し、ボタンの有効/無効を切り替えます。

```js
// 削除ボタンの有効、無効を切り替えつつ表示する  
const ShowDelete = () => {
  return (
    <Button
      icon="delete"
      mode="contained"
      onPress={deleteTask}
      // 1件でも完了したタスクがあれば、削除を表示
      disabled={!(ary.filter(item => item.get('checked')).length > 0)}
    >
      <Text>削除</Text>
    </Button>
  )
};
```

そしてボタンを押した際のイベントにて deleteTask 関数を実行します。複数のタスクが対象になるので、Promiseオブジェクトを返します。そしてPromise.allを使って処理の完了を待ちます。

データを削除したら、改めてデータを取得し直しています。もちろんaryから削除するだけでも良いでしょう。

```js
// 完了しているタスクを削除するイベント
const deleteTask = async () => {
  // チェックの有無を確認して削除処理実行
  const promises = ary.map(item => {
    if (item.get('checked')) {
      return item.delete();
    }
  });
  // Promiseを処理待ち
  await Promise.all(promises);
  // バナーでメッセージ表示
  setMessage('タスクを削除しました');
  // 改めてデータを取得し直す
  fetchTodo();
};
```

これでTodoアプリの完成です。

## まとめ

このTodoアプリではNCMBのデータストアを使って、データの登録と更新そして削除を行っています。データストアはどのようなアプリであっても使うような、基本的な機能になります。ぜひReact Nativeでの使い方をマスターしてください。

[NCMBMania/ncmb-react-native: NCMB SDK for React Native](https://github.com/NCMBMania/ncmb-react-native)

## おまけ

NCMBのReact Native SDKを使ったハンズオンは随時開催しています。ぜひチェックしてください。

[【お昼のハンズオン】React Native × NCMBでTodoアプリを作ろう \- connpass](https://ncmb.connpass.com/) など