react-nativeでiOSアプリ開発 第13回 realmをreact-nativeで扱う(3)

みなさんこんにちは個別指導塾コミット塾長、AWESOME開発担当の船津です
今回はTodoアプリでタスクの終了をフラグで管理していきます
なんか近頃Todoアプリばかり作っている気がします。

今回のgithub

参考サイト

とにかく公式アンド公式ですね、公式を舐め回すように見ました

今回作りたい機能

  • テキストを入力してエンターを押すとタスクが登録される
  • タスクを登録するとIDが自動で付与される。
  • デフォルトではアクティブなタスクが表示される

それでは、実践

完全にファイルを分割するべきだったなと思いましたが、今回はしません、、、また今度ね

触るのはindex.ios.jsのみですが、長いので分けて説明します

DB作成

  • realmのスキーマを設定します。
  • primarykeyとしてidを持っています。idは重複、変更不可
  • completedをbool型で設定します
  • created_atで作成日時を設定します
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TextInput,
  TouchableHighlight,
  Switch,
} from 'react-native'
import Realm from 'realm'
import { ListView } from 'realm/react-native'

const TodoSchema = {
  name: 'Task',
  primaryKey: 'id',
  properties: {
    id: 'int',
    name: 'string',
    completed: 'bool',
    created_at: 'date',
  }
}

let realm = new Realm({schema: [TodoSchema]})

本体

  • DBからデータを取得し、ListViewで表示します。IDはあえて表示させています。
  • ボタンを押したり、タスクを登録した際には_updateData()が実行され、dataSouce更新 → 画面更新 という流れ
  • スイッチを使ってみたかったので使いました。オンのように見えている時がfalseでオフのように見えている時がtrueだったので混乱しました
  • filteredやsortedの後のクエリ部分?の文法が独特だったのでかなり苦労しました
class realmPlayground extends Component {
  constructor(props) {
    super(props)
    var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    let src = realm.objects('Task').sorted('id').filtered('completed == false')
    this.state = ({
      dataSource: ds.cloneWithRows(src),
      data:src,
      switchValue: false,
    });
    this._renderRow = this._renderRow.bind(this)
  }

   _updateData(data){
    this.setState({
      data:data,
      dataSource: this.state.dataSource.cloneWithRows(data),
    });
  }
  _createData(){
    let tasks = realm.objects('Task')
    let date = new Date()
    if (tasks.length == 0) {
      var maxId = 0
    }
    else {
      var maxId = tasks.sorted('id')[tasks.length - 1].id
    }
    realm.write(() => {
      realm.create('Task', {
        id: maxId += 1,
        name: this.state.text,
        completed: false,
        created_at: date,
      })
    })
    let data = realm.objects('Task').filtered('completed == false')
    this._updateData(data)
  }

  _completeItem(id){
    realm.write(() => {
      var item = realm.objects('Task').filtered('id = $0',id)[0]
      item.completed = !item.completed
      console.log(item.completed)
       if (this.state.switchValue == true) {
        var data = realm.objects('Task').filtered('completed == true')
      }
      else {
        var data = realm.objects('Task').filtered('completed == false')
      }
      this._updateData(data)
    })  
  }
  _renderRow(rowData) {
    return (
      <View style={{marginTop:10}}>
        <TouchableHighlight onPress={() => {
            this._completeItem(rowData.id)
          }}
          activeOpacity={75 / 100}
          underlayColor={"rgb(210,210,210)"}>
          <Text>
            <View style={{ width: 250, height: 30, borderBottomWidth: 1, }}>
              <Text style={rowData.completed? styles.completed : ''}>{rowData.id}:{rowData.name}</Text>
            </View>
          </Text>
        </TouchableHighlight>
      </View>
    )
  }

  _showCompleted(){
    let data = realm.objects('Task').filtered('completed == true')
    this._updateData(data)
  }

  _showActive(){
    let data = realm.objects('Task').filtered('completed == false')
    this._updateData(data)
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={styles.input}>
          <TouchableHighlight onPress={() => {
              for(i = 0; i < 1000; i++){ this._createData() console.log(i) } }} activeOpacity={75 / 100} underlayColor={"rgb(210,210,210)"}>
            <Text>Press</Text>
          </TouchableHighlight>
          <Text style={styles.welcome}>
          お仕事の名前を入れてね
          </Text>
          <TextInput style={{ height: 30, width: 150, borderWidth: 1, borderColor: "rgba(0,0,0,0.5)", marginTop: 10, }} placeholder={'Type here'} placeholderTextColor={"rgba(198,198,204,1)"} onChangeText={(text) => {this.setState({text})}}
            onSubmitEditing={() => {
              this._createData()
              this.setState({text: ''})
            }}
            value={(this.state && this.state.text) || ''}
          />
        </View>
        <Switch value={(this.state && this.state.switchValue) || false} onValueChange={(value) => {
            this.setState({switchValue: value})
            if (this.state.switchValue == true) {
              this._showActive()
             }
            else {
              this._showCompleted()
           }
          }}
          tintColor={"rgba(230,230,230,1)"}
          onTintColor={"rgba(68,219,94,1)"}
        />
        <View style={styles.list}>
           <ListView enableEmptySections={true} dataSource={this.state.dataSource} renderRow={this._renderRow} />
        </View>
      </View>
    );
  }
}

スタイルとか

  • スタイルの設定をします
  • アプリの登録をします
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  input: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  list: {
    flex: 4,
    justifyContent: 'center',
  },
  completed: {
    textDecorationLine: 'line-through',
    textDecorationStyle: 'solid',
  },
});

AppRegistry.registerComponent('realmPlayground', () => realmPlayground);

ちゃんと動くとこんな感じになりますよん

タスクを登録するとこんな感じ

react-nativeでiOSアプリ開発 第13回 realmをreact-nativeで扱う(3)

タスクを押すと表示されなくなりますが、ボタンをオンにすると表示されます

react-nativeでiOSアプリ開発 第13回 realmをreact-nativeで扱う(3)
react-nativeでiOSアプリ開発 第13回 realmをreact-nativeで扱う(3)

いっぱい作ると重くなりますね

上に設置されているpressボタン、気にならないでしょうか?
実はこれ、ダミーデータ作成用のボタンです。

<TouchableHighlight onPress={() => {
              for(i = 0; i < 1000; i++){ this._createData() console.log(i) } }} activeOpacity={75 / 100} underlayColor={"rgb(210,210,210)"}>
            <Text>Press</Text>
          </TouchableHighlight>

作成中

いっぱい出来てます!
react-nativeでiOSアプリ開発 第13回 realmをreact-nativeで扱う(3)

重いぞい

ボタンを押しても反応が鈍いですね、当たり前ですが…
react-nativeでiOSアプリ開発 第13回 realmをreact-nativeで扱う(3)

最後に

Todoアプリはrailsなどでは一発で作れる簡単なアプリなのですが、react-native,realmでは勝手が違って難しかったです。
とにかく資料が少なかったのでstackoverflowをつまみ食いしています。
次回は日付でソートしたり、別タブ表示にしたりしてみましょう。

Instagram Feed

Load More

Instagram

専務取締役

funatsukeisuke

WEBと教育を組み合わせて何かおもしろいことをやってやろうと画策しています。AWESOMEでは開発を担当、個別指導塾コミットでは塾長と2足の草鞋を履きながら日々勉強しています。

他の投稿を見る →