Edited at

Vue NativeでTodoアプリを作ろう その1

More than 1 year has passed since last update.


はじめに

VueNativeが話題です。公開してから数日でgithubスター数3000を超えました。

HelloWorldの記事もいいね数多め。:さっそくVue NativeでHello Worldしてみた - Qiita

ということでVue Nativeを触ってみます。

ゴールはTodoアプリですが、この記事では一旦コンソール出力までを実装します。


作り方

今回はReactNativeアプリをクローンしてみます。以下の記事をVueNativeでやってみたです

VueNativeは中身的にはReactNativeの技術の上に乗っているので、エラー処理なんかはReactNativeの知識が求められそう。一度目を通しても良いかもしれません。


まずはプロジェクト作成

Installation — Vue Native

Vue Native Cliを使ってアプリを作ります。

これを使うために更にcreate-react-native-appが必要になるので、global installします。

yarn global add create-react-native-app

yarn global add vue-native-cli
vue-native init todoapp
cd todoapp/


アプリ起動

yarn start

するとQRコードとともにこんな結果がでてきます。

image.png

iでiosエミュレーターが起動します。

clipboard.png


補足

これはさっき導入したcreate-react-native-appによって提供されている開発環境でexpoとfacebookがコラボして作られたツールです。

そもそも、Vue Nativeは内部的にReact Nativeをラップして実装しているようで、vue-native-clicreate-react-native-appをラップして実装しているのでしょう。

こちらのcreate-react-native-appは、xcodeAndroid Studioを経由せず、Expoを使ってアプリが実行されます。

xcodeAndroid Studioのビルド環境が絡むと(特にAndroid)、地雷踏んだときにめっちゃ時間かかります。Expoを使ってみた感じ、アプリケーションの実装を考えるだけで済むため、開発者に有意義なツールです。

とはいえカスタマイズするとなると脱Expoをしないといけないので、導入時のタイミングにはありかもしれないです。

ちなみに、QRコードを使って手元のスマホアプリから確認するときは同じネットワーク(WiFi)に接続してくださいね。(この192.168.160.30はローカルIPアドレスなので)


色を変えてみよう

App.vueを以下の内容で編集してみます。


App.vue

<template>

<view class="container">
<text class="welcome">{{message}}</text>
</view>
</template>

<script>
export default {
data: function() {
return {
message: "Vue Nativeへようこそ"
}
}
}
</script>

<style>
.container {
background-color: #333;
align-items: center;
justify-content: center;
flex: 1;
}
.welcome {
color: white;
font-size: 20px;
margin: 20px;
}
</style>


clipboard.png


コンポーネント作成

Todoの入力フォームと、そのTodoをリストに追加するボタンを追加していきます。

src/TodoInput.vueを作ります。


TodoInput.vue

<template>

<view class="container">
<text-input class="text-input" />
<touchable-opacity class="button">
<text class="button-text">追加</text>
</touchable-opacity>
</view>
</template>

<script>
export default {}
</script>

<style>
.container {
flex-direction: row;
padding: 20px;
}
.text-input {
background-color: white;
margin-right: 5px;
flex: 3;
}
.button {
flex: 1;
background-color: #008080;
margin-left: 5px;
align-items: center;
justify-content: center;
padding-top: 10px;
padding-bottom: 10px;
}
.button-text {
color: white;
font-weight: normal;
}
</style>


ちなみにReactNativeで書くとこうなります。


TodoInput@ReactNative

import React, { Component } from 'react';

import {
View,
Text,
TouchableOpacity,
TextInput,
StyleSheet,
} from 'react-native';

const styles = StyleSheet.create({
container: {
flexDirection: 'row',
padding: 20,
},
textInput: {
flex: 3,
backgroundColor: '#FFF',
marginRight: 5,
},
button: {
flex: 1,
backgroundColor: '#008080',
marginLeft: 5,
alignItems: 'center',
justifyContent: 'center',
paddingTop: 10,
paddingBottom: 10,
},
buttonText: {
color: '#FFF',
fontWeight: '500',
}
});

export default class TodoInput extends Component {
render() {
return (
<View style={styles.container}>
<TextInput style={styles.textInput}/>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>追加</Text>
</TouchableOpacity>
</View>
);
}
}



コンポーネントについて

VueNativeはReactNativeのコンポーネントを使って実装します。

react-vueをforkして実装していることから、ReactNativeのコンポーネント名をキャメルケース(CamelCace)からケバブケース(kebab-case)に置き換えて使うイメージで大丈夫です。


Introducing Vue Native – GeekyAnts Blog


ここでは<TouchableOpacity><touchable-opacity>と書きます。


スタイル

ReactNativeでは、StyleSheetを使い、CSSをjsのオブジェクトとして定義しています(CSS in JS)。つまり、純粋なCSSでは書けません。

Vue NativeではCSSで書けます。いいですね。

ReactNativeではこうで


これが

  buttonText: {

color: '#FFF',
fontWeight: '500',
}

VueNativeではこう書けます


こう

.button-text {

color: white;
font-weight: normal;
}

. . .

ちなみに対応していないCSSもあるみたいです。

font-size: large;

適用されません。

VueのCSSから、ReactNativeのstyleにマッピングがうまくできてない感じがします。

react-vueでマッピングができてない?)

buildエラーになるパターンと、そうならないパターンに遭遇しましたが、条件を追求できていないので分かり次第追記します。


コンポーネントの読み込み

App.vueTodoInput.vueを組み込んでみましょう。

<template>

<view class="container">
<view class="main">
<text-input />
</view>
</view>
</template>

<script>
import TextInput from './src/TodoInput';
export default {
components: {
TextInput
}
}
</script>

<style>
.container {
background-color: #333;
flex: 1;
padding-top: 40px;
align-items: center;
}
.main {
flex: 1;
max-width: 400px;
align-items: center;
}
</style>


  1. scriptタグでTextInputをインポート

  2. scriptタグでcomponentsとしてTextInputを定義

  3. ケバブケースでコンポーネントを記述: <text-input />

するとこんな感じで画面に表示されるようになります。

clipboard.png


コンソール出力

テキストを入力して追加ボタンを押すとconsoleに出力できるようにしてみましょう。

App.vueは以下の編集をします。

-      <text-input />

+ <text-input
+ :on-add='_onPress'
+ />


export default {
components: {
TextInput
- }
- }
+ },
+ methods: {
+ _onPress : (text) => {
+ console.log(text);
+ },
+ }
+ }


  • App.vueで関数を定義

  • その関数_onPressを、on-add(onAdd)としてTextInputに渡す

つぎに、TodoInput.vueの編集です。

-        <text-input class="text-input" />

- <touchable-opacity class="button">
+ <text-input class="text-input" v-model="newText" />
+ <touchable-opacity class="button" :on-press="addTodo">

<script>

export default {
+ props: {
+ onAdd: Function
+ },
+ methods: {
+ addTodo: function() {
+ this.onAdd(this.newText)
+ },
+ }
}
</script>

テキストを入力して追加ボタンを押してみてください。

すると

clipboard.png

ターミナルにconsole.logの内容が出力されます。

xcodeを使った場合だとchromeのコンソールに出力されますが、こちら(expo)はターミナルに出力される感じです。

一旦はここまでです。

ソースはgithubにあげてますので、わからなければこちらからどうぞ!