ローディング中

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

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

今回のgithub
https://github.com/keisukefunatsu/app-education/tree/49997ee4701ad696c85d77539541edeadecb1730

目次

参考サイト

とにかく公式アンド公式ですね、公式を舐め回すように見ました
https://realm.io/docs/react-native/latest/#getting-started

今回作りたい機能

  • テキストを入力してエンターを押すとタスクが登録される
  • タスクを登録すると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);

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

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

Screen Shot 2016-08-24 at 17.41.37

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

Screen Shot 2016-08-24 at 17.41.48
Screen Shot 2016-08-24 at 17.41.55

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

上に設置されている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>

作成中

いっぱい出来てます!
Screen Shot 2016-08-24 at 17.49.11

重いぞい

ボタンを押しても反応が鈍いですね、当たり前ですが…
Screen Shot 2016-08-24 at 17.50.15

最後に

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

ホームページ・デザイン制作のご相談・ご依頼は

079-451-5881

68ED4C65-BA1E-46D0-A7AC-B9869923C696 Created with sketchtool. A07C553F-CF16-4B7D-94FE-D36AE0A6297D Created with sketchtool. 37B7D8F4-7A18-4725-9EC6-595ABDF69D64 Created with sketchtool. 95DFB680-1EDF-4199-BC4A-BB6752EBA23C Created with sketchtool. 02DDF754-E1DB-4EF2-B6BB-C884722938C4 Created with sketchtool. NEW! 1A95E369-6469-4C46-B38F-F83410B928B0 Created with sketchtool. Group 5Group 2Group 4Group 3E4FC8CF2-721D-4699-8162-18E886C432C1 Created with sketchtool.