LoginSignup
3
4

More than 5 years have passed since last update.

Vue NativeでNativeBaseのStyleProviderを利用する

Last updated at Posted at 2019-03-17

はじめに

React NativeのUIコンポーネントライブラリとしてよく知られているNativeBaseですが、Vue Nativeでも簡単に組み込んで利用することができます。

個人的に開発しているVue NativeアプリケーションでもNativeBaseを利用しているのですが、StyleProviderを用いたテーマの適用で少しハマったので、その時の解消法を紹介します!

環境構築

初めにNativeBaseを利用したVue Nativeアプリケーションの環境構築を行います。

Vue Nativeプロジェクトの作成

公式ドキュメントを参考に以下のコマンドで作成します。


$ npm install -g vue-native-cli
$ vue-native init <projectName> // Initializes crna project
$ vue-native init <projectName> --no-crna // Initializes react-native project
$ cd <project-name>

また、Vue Nativeプロジェクトの作成が完了したら以下のコマンドでアプリケーションを起動することができます。


$ npm start

NativeBaseインストール

こちらも公式ドキュメントを参考に以下のコマンドよりインストールを行います。


$ npm install native-base --save

インストール完了後、以下のようにGlobalにNativeBaseのコンポーネントを登録し、Vue Nativeアプリケーション内から利用することができます。


import Vue from "vue-native-core";
import { VueNativeBase } from "native-base";

// registering all native-base components to the global scope of the Vue
Vue.use(VueNativeBase);

簡単なVue Nativeアプリケーションの作成

環境構築が完了したら、NativeBaseを利用した簡単なVue Nativeアプリケーションを作成します。

作成にあたっては、以下のサンプルアプリケーションを参考に行います。
https://github.com/GeekyAnts/KitchenSink-Vue-Native

src/boot/setup.vue

<template>
  <app-loading v-if="!isAppReady" />
  <app v-else />
</template>

<script>
import Vue from 'vue-native-core';
import { VueNativeBase } from 'native-base';
import { AppLoading } from 'expo';
import App from '../App.vue';

// ここでNativeBaseのコンポーネントをGlobalに登録
Vue.use(VueNativeBase);

export default {
  components: { App, AppLoading },
  data: function() {
    return {
      isAppReady: false,
    };
  },
  created: function() {
    this.loadFonts();
  },
  methods: {
    loadFonts: async function() {
      try {
        this.isAppReady = false;
        await Expo.Font.loadAsync({
          Roboto: require('native-base/Fonts/Roboto.ttf'),
          Roboto_medium: require('native-base/Fonts/Roboto_medium.ttf'),
          Ionicons: require('@expo/vector-icons/fonts//Ionicons.ttf'),
        });
        this.isAppReady = true;
      } catch (error) {
        console.log('some error occured', error);
        this.isAppReady = true;
      }
    },
  },
};
</script>

また、今回スクリーンはHomeのみ実装し、NativeBaseのnb-textコンポーネントを表示します。

src/screens/home/index.vue

<template>
  <view class="container">
    <nb-button block primary>
      <nb-text>Primary</nb-text>
    </nb-button>
  </view>
</template>

<script>
export default {
  props: {
    navigation: {
      type: Object,
    },
  },
};
</script>

<style>
.container {
  background-color: white;
  align-items: center;
  justify-content: center;
  flex: 1;
}
.text-color-primary {
  color: blue;
}
</style>

Simulatorでアプリケーションを起動すると、ボタンが中央に表示されたHomeスクリーンが表示されます。

スクリーンショット 2019-03-17 18.20.29.png

現状ではデフォルトのデザインが適用されていますが、これからアプリケーションのテーマをカスタマイズしていきます!

StyleProviderを利用してMaterial Designのテーマを適用

NativeBaseではStyleProviderを利用してアプリケーションのテーマをカスタマイズすることが出来ます。
https://docs.nativebase.io/Customize.html#Customize

そこで今回はMaterial Designのテーマ利用してカスタマイズします。

native-base-theme取得

カスタマイズにあたって、初めに以下のコマンドを実行し、native-base-themeを取得します。


# 以下のコマンドでnative-base-themeを生成
$ node node_modules/native-base/ejectTheme.js

するとRootディレクトリ配下に、native-base-themeディレクトリが生成されます。
native-base-themeにはcomponentvariablesディレクトリが含まれており、今回はディレクトリをsrc/theme配下に移動させました。


# 生成したファイル群をsrc/theme配下に移動
$ mv native-base-theme src/theme

StyleProviderでカスタマイズ

native-base-themeを取得したら、StyleProviderコンポーネントを利用してアプリケーションのテーマをカスタマイズします。

カスタマイズの方法は、テーマを反映させたいコンポーネントをStyleProviderコンポーネントでラップしてあげることで実現できます。
その際、適用したいテーマをvariablesからimportし、themeメソッドを介してStyleProviderstyleプロパティにて指定します。

StyleProviderコンポーネントもVue.use(VueNativeBase);により、nb-style-providerとしてGlobalなVue.jsコンポーネントで定義されているため、以下のように実装しました。

src/boot/setup.vue

<template>
  <app-loading v-if="!isAppReady" />
  <!-- nb-style-providerコンポーネントを追記し、Material Designのstyleを指定 -->
  <nb-style-provider v-else :style="getTheme(material)">
    <app />
  </nb-style-provider>
</template>

<script>
// ・・・省略
// getTheme, materialをimport
import getTheme from '../theme/components';
import material from '../theme/variables/material';

// ・・・省略

export default {
  components: { App, AppLoading },
  data: function() {
    return {
      isAppReady: false,
      // getTheme, materialをそれぞれdataに追加
      getTheme: getTheme,
      material: material,
    };
  },
  // ・・・省略
};
</script>

Warningが発生

上記実装を行ったところ、以下のようなWarningが発生しました。

スクリーンショット 2019-03-17 18.42.55.png

Warning: Failed prop type: Invalid prop style of type array supplied to StyleProvider, expected object.

内容としては、StyleProviderstyleプロパティにObject型を期待しているようですが、nb-style-providerコンポーネントから渡していたgetTheme(material)がArray型で渡されてしまっていたようです。

ただgetTheme(material)の返却値を確認してみてもObject型で返却されているため、内部的にVue.jsコンポーネントからReactコンポーネントへ変換される時にstyleプロパティがArray型として変換されているのかも。。。
(ここはまだちゃんと調べられていないため、間違っていたらすみません)

修正方法を探していたところ、GithubのIssueにも同様のコメントをしている方を発見。
https://github.com/GeekyAnts/KitchenSink-Vue-Native/issues/6

上記Issueのコメントを確認してみると以下のような回答がされておりました。

You'll have to create a separate react component to use theme for now and then import that theme as root component within your vue file.

現状、StyleProviderを利用してテーマを適用するためにはReactコンポーネントを実装して、Vue.jsのファイルからimportして利用する必要があるようでした。

NativeBase用のプラグインを実装

上記を踏まえて、nb-style-providerコンポーネントは利用せず、新たにMaterial Designのテーマを適用したReactコンポーネント(StyleProviderMaterial)を実装します。

ただ、他のNativeBaseコンポーネントがVue.jsのGlobalなコンポーネントとして定義されているのに対し、StyleProviderMaterialだけ毎回importして利用するのは面倒臭いし、違和感がある。。。

そこで、NativeBase用のプラグインを自作し、Vue.use()の際、ReactコンポーネントStyleProviderMaterialをVue.jsコンポーネントnb-style-provider-materialとしてGlobalに登録するようにしました。
Vue.jsのプラグインについてはこちら

src/plugins/native-base.js

import React, { Component, Children } from 'react';
import { VueNativeBase, StyleProvider } from 'native-base';
import getTheme from '../theme/components';
import material from '../theme/variables/material';

// ReactコンポーネントとしてMaterial esignのテーマを指定したStyleProviderを生成
class StyleProviderMaterial extends Component {
  render() {
    const { children } = this.props;

    return (
      <StyleProvider style={getTheme(material)}>
        {Children.only(children)}
      </StyleProvider>
    );
  }
}

// Vue.jsプラグインの作成
const NativeBasePlugin = {
  install(Vue, options) {
    // ついでにVueNativeBase.install(Vue)の呼び出しもこちらで行う
    Vue.use(VueNativeBase);
    // 上記で作成したReactコンポーネントをVue.jsのglobalなコンポーネントとして設定
    Vue.component('nb-style-provider-material', StyleProviderMaterial);
  },
};

export default NativeBasePlugin;

nb-style-provider-materialの利用

作成したプラグインを呼び出し、Warningが発生していたnb-style-providernb-style-provider-materialに置き換えます。

src/boot/setup.vue
<template>
  <app-loading v-if="!isAppReady" />
  <!-- plugins/native-base.jsでglobalに定義したnb-style-provider-materialコンポーネント -->
  <nb-style-provider-material v-else>
    <app />
  </nb-style-provider-material>
</template>

<script>
import Vue from 'vue-native-core';
import { AppLoading } from 'expo';
import App from '../App.vue';
// getTheme, materialのimportを削除し、NativeBaseのプラグインをimport
import NativeBase from '../plugins/native-base.js';

// プラグインのNativeBase.install(Vue)を呼び出し
Vue.use(NativeBase);

export default {
  components: { App, AppLoading },
  data: function() {
    return {
      isAppReady: false,
      // getTheme, materialの定義を削除
    };
  },
  // ・・・省略
};
</script>

Material Designテーマの適用

改めてSimulatorを確認したところ、Warningが解消され、Material Designのテーマが適用されていることが確認できました!

スクリーンショット 2019-03-17 19.04.01.png

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4