みなさんこんにちは個別指導塾コミット塾長、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をつまみ食いしています。
次回は日付でソートしたり、別タブ表示にしたりしてみましょう。




