みなさんこんにちは個別指導塾コミット塾長、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);
ちゃんと動くとこんな感じになりますよん
タスクを登録するとこんな感じ
タスクを押すと表示されなくなりますが、ボタンをオンにすると表示されます
いっぱい作ると重くなりますね
上に設置されている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>
作成中
いっぱい出来てます!
重いぞい
ボタンを押しても反応が鈍いですね、当たり前ですが…
最後に
Todoアプリはrailsなどでは一発で作れる簡単なアプリなのですが、react-native,realmでは勝手が違って難しかったです。
とにかく資料が少なかったのでstackoverflowをつまみ食いしています。
次回は日付でソートしたり、別タブ表示にしたりしてみましょう。