はじめに
前回、React NativeをAndroid Studioと組み合わせて インストールし、HelloWorldを出せるところまで
たどり着きました。
今回は一足飛びで、React NativeとReduxをフロントエンドに使い、バックエンドにRailsを用いた
掲示板アプリを作ってみましょう。
前提として、Railsはそれなりにわかっている。Reactもよく分かっている。Reduxも知っている。
ぐらいのレベルを前提にしています。
出来上がったアプリは、デザイン的にどんくさいですが、これは私がまだReactNativeの
スタイルの方法を学んでいないためです。まぁそれはおいおいブラッシュアップすることとしましょう。
ソースはすべてGitHubで公開しています。利用方法など含めて、記事の最後に記載しておきます。
機能一覧
掲示板一覧が表示される
掲示板を選択したら、対象のコメント一覧が表示される
コメントを投稿できる
機能はこの3つだけ。掲示板も追加できたほうがいいのでしょうが・・
あまり欲張ってあれこれ実装すると、なにを説明しているかわからなくなるので、今回は
カットしておきましょう。
出来上がりのイメージからパーツ構成を考える
出来上がりの画面イメージは以下のようなものです。いかにもどんくさい画面ですが、
これは私がReact Nativeのスタイルの作法がわかっていないためですので、勘弁ください。
とりあえず、この画面イメージから、どんなパーツ(Reactのコンポーネント)が必要となるか
考えてみましょう。ざっと以下のようなイメージになると思います。
アプリが持つべき、ステートとイベントを考える
画面パーツは考え終わったので、次にアプリが持つステートとイベントを考えましょう。
ステート
現在アクティブな掲示板
アクティブな掲示板に投稿されたコメント群
投稿ユーザー
投稿コメント
CSRF Token
大体この5つとなります。
投稿ユーザーと投稿コメントは、ステートにしなくても良いのかもしれませんが、Redux風に記述しようとすると
ステートとした方が処理しやすいので、ステートとします。
CSRF Tokenとは、バックエンドのRailsサーバーに対してPOST処理をするときに必要となる認証用のキーみたいなものです。
とりあえず、必要なんだなぁ・・・ぐらいに考えておいてください。
イベント
掲示板を選択する
投稿ユーザーを選択する
投稿コメントを入力する
掲示板にコメントを投稿する
投稿ユーザーの選択とは、本来の掲示板の機能では必要ではありませんが、
ログイン処理などを設けない、今回説明するこのアプリでは、投稿のたびに「私は誰ですよ」と
ユーザーも選択して、コメントを投稿することにします。
バックエンドであるRailsサーバーに必要な機能
バックエンド(サーバーサイド)のRailsアプリに必要な機能をリストアップしてみましょう。
掲示板一覧を取得
投稿ユーザー一覧を取得
対象掲示板のコメント一覧を取得
コメントを投稿
Railsでバックエンド処理を実装する
Railsは分かっている前提ですので・・、ざーーっと説明します。
目標となるファイル構成は以下のような感じです。
まずはRailsプロジェクトと、React Nativeプロジェクトの親フォルダを作りましょう。
[bash]
$ cd
$ mkdir workspace
$ cd workspace
$ mkdir reactnative_rails_board
[/bash]
Railsプロジェクト作成
[bash]
$ cd reactnative_rails_board
$ rails new rnative_rails
[/bash]
Gemファイルを調整して、bundle install
[bash]
$ cd rnative_rails
$ nano Gemfile
[/bash]
末尾に1行追記
[bash]
gem ‘therubyracer’, platforms: :ruby
[/bash]
動作確認
bundle install して、Railsサーバー起動
[bash]
$ bundle install
$ rails s
[/bash]
ここまでのところを動作確認します。
ブラウザーで
http://localhost:3000
にアクセスしてください。以下のような画面が出れば成功です。
モデル作成、サンプルデータ作成
Railsのモデルを作成し、サンプルデータをSeedファイル(CSV)として読み込める状態にしましょう。
モデルの作成
[bash]
$ rails g model board title:string description:text
$ rails g model user name:string sex:integer age:integer
$ rails g model comment board_id:integer user_id:integer comment:text
[/bash]
モデルの調整
rnative_rails/app/models/comment.rb
[bash]
class Comment < ApplicationRecord
belongs_to :user
end
[/bash]
マイグレート
[bash]
$ rake db:migrate
[/bash]
出来上がったイメージはこんな感じ。
Seedデータの作成
何もないところからデータ投稿までつくり上げるのには時間がかかるので、シード(seed)データを
作っておいて、まずはそのデータを読んで、一覧表示することぐらいから始めましょう。
db/csv/boards.csv
[bash]
1,ReactJSを学ぼう,あいうえお
2,ReactJS と Rails連携,かきくけこ
3,ReactJS 発展編,さしすせそ
4,jQuery入門,たちつてと
5,jQuery得意な人集まれ,なにぬねの
6,AngularJS入門,はひふへほ
7,vue.jsってなんぞ,まみむめも
[/bash]
db/csv/users.csv
[bash]
1,花子,2,23
2,太郎,1,30
3,幸次郎,1,15
4,浩輝,1,40
5,大樹,1,35
6,すず,2,28
7,雅代,2,38
[/bash]
db/csv/comments.csv
[bash]
“1”,”1″,”2″,”ReactはFacebookが開発しているUI(MV*フレームワークでいうViewのようなもの)に特化したJavaScriptライブラリです。 ”
“2”,”1″,”3″,”大きな特徴としてVirtual DOM(仮想DOM)と呼ばれるレンダリング機構がそなわっており、Webページの表示を従来の .”
“3”,”1″,”3″,”公式サイトに、「A JavaScript library for building user interfaces」とあるように、React.jsはUIを構築するためのライブラリです。”
“4”,”1″,”3″,”フレームワークでなくあくまでUIを構築するだけのライブラリで、MVCでいうところのVのみの機能を提供します。”
“5”,”1″,”7″,”最近フロントエンドでfacebook/reactをずっと使っている。世界的には一部のエンジニアの間で流行っているのだが、国内だとqiitaのタグ等を見てもどうも少ない。”
“6”,”2″,”7″,”はじめにreact-railsという、ReactをAsset Pipelineに乗せて使えるようにしてくれるruby gemsがある。 この記事では、これを使用してReactの公式tutorialを進めていく。”
“7”,”2″,”4″,”既存のRailsプロジェクトの中でReact.jsを利用する機会があったので、その時にやったことについてまとめてみます。 私自身は普段RailsのサーバサイドとCoffeeScriptが中心で、最近のJavaScript開発環境についてあまりキャッチアップでき”
“8”,”2″,”5″,”RailsでSingle-Page Applicationをつくるときの自分のやり方をまとめてみます。 Gem 「JavaScriptで書かれたReactのコンポーネントからHTMLを生成する」というのをRubyでやるために、RubyのV8エンジン実装で ..”
“9”,”2″,”2″,”react-railsというReact.jsをRailsに簡単に統合できるgemを使い、React.jsについて説明します。 次のような画面をReact.jsで実装し、Reactとサーバ(Rails)間でメッセージ一覧の取得や作成をできるようにします。 ソースコードはこちらです。”
“10”,”3″,”2″,”最近のモダンなウェブフレームワークと言えば、React+Reduxですよね。でも、なんか難しそうとか、ReactってPHPみたいにViewにロジック混ざりそうとか感じて尻込みしていませんか?それはただの誤解かもしれません。React+Reduxはそんなに難易度の高い .”
“11”,”3″,”1″,”玉石混合状態にあったFluxのフレームワークも、ここ最近ではReduxが首一つ抜け出したような感じとなっています。自分はFacebook/Flux派ではありましたが、先月発売された『WEB+DB PRESS vol.92』に掲載されていた”
“12”,”3″,”6″,” React.jsとReduxを組み合わせた構成で、Webサイトを作ってみるチュートリアル(React+Redux入門)です。第一回目は、GitHub上のコードが読めるようになることを目標に解説しています。”
“13”,”3″,”3″,”目的 ReduxとES6への入門。 React.jsを(ようやく)触る機会が出て、情報量の多いFluxxorとCoffeeScriptで入門してた。 ”
“14”,”7″,”3″,”私たちはなぜReactではなくVue.jsを選んだのか Qwintryチームは最近、既存のすべてのプロジェクトのフロントエンドをVue.jsに移行しはじめました。”
“15”,”6″,”4″,”AngularJS(アンギュラージェイエス)、または Angular は、Googleと個人や企業のコミュニティによって開発されている、完全にJavaScriptで書かれたオープンソースのフロントエンドWebアプリケーションフレームワークである。MIT Licenseでライセンスされた”
“16”,”4″,”4″,”今後のWebデザイナーは、デザイン・htmlコーディング+その他の強みを求められる世の中になっていきます。今回はその強みとなりうる「jQuery」についてご説明いたします。”
“17”,”4″,”2″,”今回はjQueryの基本的な書き方として、これから「jQueryを覚えて、ブイブイ言わせてやるぜ!」と新しいスキルを身につけたいデザイナーさんには丁度いい内容かと思います。”
“18”,”5″,”2″,”今年2016年6月9日、ついに正式版がリリースされた jQuery 3。メジャーバージョンアップしたjQuery 3では、従来のバージョンから、いったい何が変わったのかを2回に分けて解説します。”
“19”,”5″,”1″,” jQueryはWeb業界の発展に大いに役立ってきました。しかし、ネイティブのJavaScriptが高度化し、かつマーケットシェアの縮小した古いブラウザをサポートする必要の薄れた現代において、jQueryを本当に使う必要があるでしょうか?必要性と”
“20”,”4″,”1″,”Webデザイナーやマークアップエンジニアのための超コンパクトなjQuery講座ができました。JavaScriptの予備知識は不要。Web制作に必要な要点だけを解説します。 (1/6)”
“21”,”7″,”6″,”双方向データバインディングに特化したVue.jsは、シンプルで学習コストも低いといわれます。第1回目はVue.jsがフレームワークとして、どんな強みをもっているのか”
“22”,”7″,”7″,”Angular、Reactと並んで海外で人気が高まっている「Vue.js」。ReactとAngularの開発経験がある著者がVue.jsをサンプルコードつきのチュートリアルを通じて特徴をまとめて解説します。2017年、新しく学び始めるきっかけにどうぞ。”
[/bash]
Seedデータをデータベースに反映するスクリプト
db/seeds.rbを編集
[bash]
require ‘csv’
CSV.foreach(‘db/csv/boards.csv’) do |row|
Board.create!(id: row[0], title: row[1], description: row[2])
end
CSV.foreach(‘db/csv/users.csv’) do |row|
User.create!(id: row[0], name: row[1], sex: row[2], age: row[3])
end
CSV.foreach(‘db/csv/comments.csv’) do |row|
Comment.create!(id: row[0], board_id: row[1], user_id: row[2], comment: row[3])
end
[/bash]
Seedデータの投入
[bash]
$ rake db:seed
[/bash]
バックエンドAPI用 AJAXコントローラー作成
[bash]
$ rails g controller board
[/bash]
コントローラーにAPI実装
rnative_rails/app/controllers/board_controller.rb
*readBoardAndUser
起動時に掲示板一覧とユーザー一覧を取得
*insertComment
コメントを投稿
*readComments
選択された掲示板に投稿されたコメント一覧を取得
X-CSRF-Tokenも返しています。
rnative_rails/app/controllers/board_controller.rb
[bash]
class BoardController < ApplicationController
def readBoardAndUser
response = {status:true}
boards = Board.all.order("created_at DESC")
users = User.all.order("id")
response[:boards] = boards
response[:users] = users
render :json=> response
end
def insertComment
response = {status:true}
c = Comment.new({board_id: params[:board_id], user_id: params[:user_id], comment: params[:comment]})
c.save()
render :json=> response
end
def readComments
response = {status:true}
response[“X-CSRF-Token”] = form_authenticity_token
recs = Comment.eager_load(:user).where(“board_id = ?”, params[:board_id])
.order(“comments.created_at DESC”).as_json(include: :user)
response[“rows”] = recs
render :json=> response
end
end
[/bash]
routes.rbの編集
rnative_rails/config/routes.rb
[bash]
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
get ‘board/readBoardAndUser’
post ‘board/insertComment’
get ‘board/readComments/:board_id’ => ‘board#readComments’
end
[/bash]
APIの動作確認
サーバーを起動して、ブラウザーにAPIのURLを入力
[bash]
$ rails s
[/bash]
http://localhost:3000/board/readBoardAndUser
下図のようにJSONが戻ってきてたら成功。
これでバックエンドの処理は完成です。
React Nativeでクライアントサイドを実装する
プロジェクトの作成
[bash]
$ cd
$ cd workspace/reactnative_rails_board/
$ react-native init rnative
[/bash]
reduxをインストール
[bash]
$ cd rnative
$ npm install –save redux react-redux
[/bash]
Android Studioから ADV Manager起動
メニューより Tools >> Android >> AVD Manager
[bash]
$ /opt/android-studio/bin/studio.sh
[/bash]
AVD Managerより仮想デバイスを起動すると、以下のような画面が表示されます。
React Nativeのデフォルトトップページを表示
[bash]
$ react-native start > /dev/null 2>&1 &
$ react-native run-android
[/bash]
以下のような画面が出れば成功です。
Reduxの標準的なフォルダを作成
Reduxのお作法に従い、標準的なフォルダを作成します。
[bash]
$ mkdir actions constants containers components reducers
[/bash]
エントリーポイント調整、App.js作成
アプリケーションのエントリーポイントである index.android.jsを調整し、
アプリケーションのトップレベルの階層である App.jsを作成します。
rnative/index.android.js
[bash]
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from ‘react’;
import {
AppRegistry,
StyleSheet,
Text,
View
} from ‘react-native’;
import App from “./components/App”;
export default class rnative extends Component {
render() {
return (
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: ‘center’,
alignItems: ‘center’,
backgroundColor: ‘#F5FCFF’,
},
});
AppRegistry.registerComponent(‘rnative’, () => rnative);
[/bash]
rnative/components/App.js
[bash]
import React, { Component } from ‘react’;
import {
AppRegistry,
StyleSheet,
Text,
View,
} from ‘react-native’;
export default class App extends Component {
constructor(props){
super(props);
}
componentDidMount() {
}
render() {
return (
React Native! and Rails5.0!!
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: ‘center’,
alignItems: ‘center’,
backgroundColor: ‘#F5FCFF’,
},
welcome: {
flex: 1,
fontSize: 20,
textAlign: ‘center’,
margin: 10,
},
});
[/bash]
動作確認
[bash]
$ react-native run-android
[/bash]
以下のように表示されればOKです。
コンポーネント群作成
既に考えたパーツ構成に従い、コンポーネント群を作っていきましょう。
rnative/components/BoardList.js
[bash]
import React from “react”;
import {
StyleSheet,
Text,
View,
ListView,
Button
} from ‘react-native’;
const BoardList = () => {
return (
This is BoardList
);
}
export default BoardList;
[/bash]
rnative/components/CommentAdd.js
[bash]
import React from “react”;
import {
StyleSheet,
Text,
TextInput,
View,
ListView,
Button,
Picker
} from ‘react-native’;
const CommentAdd = () => {
return (
This is CommentAdd
)
}
const styles = StyleSheet.create({
row:{
flex: 1,
flexDirection: “row”
},
comment: {
width: 400
},
picker: {
flex: 3,
},
btn: {
flex:2
},
});
export default CommentAdd;
[/bash]
rnative/components/CommentList.js
[bash]
import React from “react”;
import {
StyleSheet,
Text,
View,
ListView,
Button
} from ‘react-native’;
const CommentList = () => {
return (
This is CommentList
);
}
export default CommentList;
[/bash]
ラッパークラス群(container)作成
Reduxでは、イベントやプロパティを割り当てたいコンポーネントの一層上に
ラッパークラス(container)をかぶせてやる必要があります。
コンポーネントのクラスの前に「C」をつけて、クラスを作りましょう。
rnative/containers/CBoardList.js
[bash]
import {connect} from “react-redux”;
import BoardList from “../components/BoardList”;
const mapStateToProps = (state, ownProps) => {
return {
}
}
const mapDispatchToProps = (dispatch) => {
return {
}
}
const CBoardList = connect(mapStateToProps, mapDispatchToProps)(BoardList);
export default CBoardList;
[/bash]
rnative/containers/CCommentAdd.js
[bash]
import {connect} from “react-redux”;
import CommentAdd from “../components/CommentAdd”;
const mapStateToProps = (state, ownProps) => {
return {
}
}
const mapDispatchToProps = (dispatch) => {
return {
}
}
const CCommentAdd = connect(mapStateToProps, mapDispatchToProps)(CommentAdd);
export default CCommentAdd;
[/bash]
rnative/containers/CCommentList.js
[bash]
import React from “react”;
import {connect} from “react-redux”;
import CommentList from “../components/CommentList”;
const mapStateToProps = (state) => {
return {
}
}
const CCommentList = connect(mapStateToProps, null)(CommentList);
export default CCommentList;
[/bash]
Reducerの作成
既に考えてあるステートを実装するReducerを作成します。
最初は難しいかもしれませんが、こんなもんだと思って慣れてください。
rnative/reducers/root.js
[bash]
import {combineReducers} from “redux”;
import sel_board from “./sel_board”;
import comments from “./comments”;
import csrf_token from “./csrf_token”;
import sel_user from “./sel_user”;
const rootReducer = combineReducers({
sel_board: sel_board,
comments: comments,
csrf_token: csrf_token,
sel_user: sel_user
});
export default rootReducer;
[/bash]
rnative/reducers/comments.js
[bash]
const comments = (state=[], action) => {
switch (action.type) {
case “COMMENTS_READ”:
return action.comments;
default:
return state;
}
};
export default comments;
[/bash]
rnative/reducers/csrf_token.js
[bash]
const csrf_token = (state=””, action) => {
switch (action.type) {
case “TOKEN_CHANGE”:
return action.token;
default:
return state;
}
}
export default csrf_token;
[/bash]
rnative/reducers/sel_board.js
[bash]
const sel_board = (state=-1, action) => {
switch (action.type) {
case “SELECT_BOARD”:
return action.id;
default:
return state;
}
};
export default sel_board;
[/bash]
rnative/reducers/sel_user.js
[bash]
const sel_user = (state=-1, action) => {
switch (action.type) {
case “SELECT_USER”:
return action.id;
default:
return state;
}
};
export default sel_user;
[/bash]
エントリーポイント、アプリケーションのトップ階層(App.js)の調整
createStoreで作成したストアを Providerのプロパティに渡し、Providerの子供に
App を設定します。
rnative/index.android.js
[bash]
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from ‘react’;
import {
AppRegistry,
StyleSheet,
Text,
View
} from ‘react-native’;
import {Provider} from “react-redux”;
import {createStore} from “redux”;
import App from “./components/App”;
import rootReducer from “./reducers/root”;
export default class rnative extends Component {
constructor(props){
super(props);
}
render() {
let store = createStore(rootReducer);
return (
);
}
}
AppRegistry.registerComponent(‘rnative’, () => rnative);
[/bash]
アプリケーションのコンポーネントの骨格を作成します。
実際のコンポーネントではなくラッパークラス(container)でレイアウトを作ります。
rnative/components/App.js
[bash]
import React, { Component } from ‘react’;
import {
AppRegistry,
StyleSheet,
Text,
View,
} from ‘react-native’;
import CBoardList from “../containers/CBoardList”;
import CCommentList from “../containers/CCommentList”;
import CCommentAdd from “../containers/CCommentAdd”;
export default class App extends Component {
constructor(props){
super(props);
}
componentDidMount() {
}
render() {
return (
React Native! and Rails5.0!!
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: ‘center’,
alignItems: ‘center’,
backgroundColor: ‘#F5FCFF’,
},
welcome: {
flex: 1,
fontSize: 20,
textAlign: ‘center’,
margin: 10,
},
});
[/bash]
動作確認
ここまでのところで動作確認します。
以下のような画面が出ればOKです。
[bash]
$ react-native run-android
[/bash]
掲示板一覧を読み込み、表示する
さて、いよいよ、サーバーのAPIにアクセスして、データを読み込み、表示してみましょう。
その前に準備として、ActionCreatorの作成と、定数ファイルを作っておきましょう。
既に考えてある、イベントから、ActionCreatorを作ります。
これも慣れてください。
rnative/actions/index.js
[bash]
export const select_board = (id) =>{
return {
type: “SELECT_BOARD”,
id: id
};
}
export const comments_read = (comments) =>{
return {
type: “COMMENTS_READ”,
comments: comments
};
}
export const token_change = (token) => {
return {
type: “TOKEN_CHANGE”,
token: token
}
}
export const select_user = (id) =>{
return {
type: “SELECT_USER”,
id: id
};
}
[/bash]
アプリで使う定数群を扱うファイルです。
今回はAPIサーバーが起動している開発PCのIPアドレスをセットしておきます。
ここは、ご自身の開発マシンのIPアドレスをセットしてください。
rnative/constants/index.js
[bash]
export const HOST_ADDR=’192.168.11.6:3000′;
[/bash]
アプリの起動時にAPIサーバーにアクセスし、掲示板一覧・ユーザー一覧を取得(readInit)し、
CBoardListとCCommentAdd のプロパティにセット。
rnative/components/App.js
[bash]
import React, { Component } from ‘react’;
import {
AppRegistry,
StyleSheet,
Text,
View,
ListView
} from ‘react-native’;
import {HOST_ADDR} from “../constants/index”;
import CBoardList from “../containers/CBoardList”;
import CCommentList from “../containers/CCommentList”;
import CCommentAdd from “../containers/CCommentAdd”;
export default class App extends Component {
constructor(props){
super(props);
let dsBoard = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {dataSourceBoard: dsBoard, users: []};
}
componentDidMount() {
this.readInit();
}
render() {
return (
React Native! and Rails5.0!!
);
}
readInit() {
let dsBoard = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
fetch(‘http://’ + HOST_ADDR + ‘/board/readBoardAndUser’)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
dataSourceBoard: dsBoard.cloneWithRows(responseJson.boards),
users: responseJson.users
});
})
.catch((error) => {
console.error(error);
});
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: ‘center’,
alignItems: ‘center’,
backgroundColor: ‘#F5FCFF’,
},
welcome: {
flex: 1,
fontSize: 20,
textAlign: ‘center’,
margin: 10,
},
});
[/bash]
rnative/containers/CBoardList.js
[bash]
import {connect} from “react-redux”;
import {select_board} from “../actions/index”;
import {HOST_ADDR} from “../constants/index”;
import BoardList from “../components/BoardList”;
import {comments_read, token_change} from “../actions/index”;
const mapStateToProps = (state, ownProps) => {
return {
dsBoard: ownProps.dsBoard,
sel_board: state.sel_board
}
}
const mapDispatchToProps = (dispatch) => {
return {
onBoardSelect: (id) => {
dispatch(select_board(id));
}
}
}
const CBoardList = connect(mapStateToProps, mapDispatchToProps)(BoardList);
export default CBoardList;
[/bash]
読み込まれたデータをループで展開し、1行を表す BoardLineをn個作る。
rnative/components/BoardList.js
[bash]
import React from “react”;
import {
StyleSheet,
Text,
View,
ListView,
Button
} from ‘react-native’;
import BoardLine from “./BoardLine”
const BoardList = ({dsBoard, sel_board, onBoardSelect}) => {
return (
{
let act = rowData.id == sel_board ? true : false;
return (
onBoardSelect(id)}
/>
)
}}
/>
);
}
export default BoardList;
[/bash]
掲示板の1行を意味するBoardLineクラスの作成
[bash]
import React from “react”;
import {
StyleSheet,
Text,
View,
Button
} from ‘react-native’;
const BoardLine = ({active, rowData, onPress}) => {
let styleTitle = [styles.title];
if (active){
styleTitle = [styles.title, styles.active];
}
return (
{rowData.title}
{
onPress(rowData.id)
}}
title=”select” />
);
}
const styles = StyleSheet.create({
row:{
flex: 1,
flexDirection: “row”
},
title: {
width: 300
},
active: {
backgroundColor: “#58aacc”
},
});
export default BoardLine;
[/bash]
Railsサーバーを起動して、動作確認
仮想デバイス(Android)から接続しなければならないので、b オプションをつけて
サーバーを起動
[bash]
$ cd
$ cd workspace/reactnative_rails_board/rnative_rails/
$ rails s -b 0.0.0.0
[/bash]
[bash]
$ cd
$ cd workspace/reactnative_rails_board/rnative
$ react-native run-android
[/bash]
めでたく掲示板一覧が表示されましたか?
コメント一覧を読み込み、表示
まず、読み込み部分。
これは掲示板一覧の右側にある「SELECT」ボタンがクリックされた時に
読み込みます。
rnative/containers/CBoardList.js
[bash]
import {connect} from “react-redux”;
import {select_board} from “../actions/index”;
import {HOST_ADDR} from “../constants/index”;
import BoardList from “../components/BoardList”;
import {comments_read, token_change} from “../actions/index”;
const mapStateToProps = (state, ownProps) => {
return {
dsBoard: ownProps.dsBoard,
sel_board: state.sel_board
}
}
const mapDispatchToProps = (dispatch) => {
return {
onBoardSelect: (id) => {
dispatch(select_board(id));
readCommentsAndRefresh(id, dispatch);
}
}
}
const readCommentsAndRefresh = (id, dispatch) =>{
fetch(‘http://’ + HOST_ADDR + ‘/board/readComments/’ + id)
.then((response) => response.json())
.then((responseJson) => {
dispatch(comments_read(responseJson.rows));
dispatch(token_change(responseJson[‘X-CSRF-Token’]));
})
.catch((error) => {
console.error(error);
});
}
const CBoardList = connect(mapStateToProps, mapDispatchToProps)(BoardList);
export default CBoardList;
[/bash]
データを読み込んだあと
dispatch(comments_read(responseJson.rows));
で、commentsステートが変化するので、それに合わせて表示を変える部分を実装しましょう。
rnative/containers/CCommentList.js
[bash]
import React from “react”;
import {connect} from “react-redux”;
import CommentList from “../components/CommentList”;
const mapStateToProps = (state) => {
return {
datas: state.comments
}
}
const CCommentList = connect(mapStateToProps, null)(CommentList);
export default CCommentList;
[/bash]
コメント一覧のコンポーネントです。
rnative/components/CommentList.js
[bash]
import React from “react”;
import {
StyleSheet,
Text,
View,
ListView,
Button
} from ‘react-native’;
import CommentLine from “./CommentLine”
const CommentList = ({datas}) => {
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
ds = ds.cloneWithRows(datas);
return (
{
return (
)
}}
/>
);
}
export default CommentList;
[/bash]
コメントの1行を表すコンポーネントです。
rnative/components/CommentLine.js
[bash]
import React from “react”;
import {
StyleSheet,
Text,
View,
Image,
} from ‘react-native’;
import {HOST_ADDR} from “../constants/index”;
const CommentLine = ({rowData}) => {
let pic = {
uri: ‘http://’ + HOST_ADDR + ‘/images/hito-‘ + rowData.user.id + ‘.jpg’
};
return (
{rowData.user.name}
{rowData.comment}
);
}
const styles = StyleSheet.create({
row:{
flex: 1,
flexDirection: “row”,
padding: 5
},
name: {
width: 50
},
comment: {
width: 280
},
});
export default CommentLine;
[/bash]
画像ファイルを配置
投稿者のアイコンイメージを作ってありますので、下記のファイルを手作業で
railsのルートフォルダ/public/images/ フォルダ配下にコピーしてください。
動作確認
起動して、掲示板をどれか選択してみてください。
以下のようなページが表示されれば成功です。
[bash]
$ react-native run-android
[/bash]
コメント投稿機能
最後にコメント投稿機能を実装します。
rnative/containers/CCommentAdd.js
[bash]
import {connect} from “react-redux”;
import {HOST_ADDR} from “../constants/index”;
import {comments_read,select_user} from “../actions/index”;
import CommentAdd from “../components/CommentAdd”;
const mapStateToProps = (state, ownProps) => {
return {
sel_board: state.sel_board,
users: ownProps.users,
current_token: state.csrf_token,
sel_user: state.sel_user
}
}
const mapDispatchToProps = (dispatch) => {
return {
onCommentPost: (sel_board, user_id, comment, token) => {
fetch(‘http://’ + HOST_ADDR + ‘/board/insertComment’, {
method: ‘POST’,
headers: {
‘Accept’: ‘application/json’,
‘Content-Type’: ‘application/json’,
‘X-CSRF-Token’: token ,
},
body: JSON.stringify({
board_id: sel_board,
user_id: user_id,
comment: comment,
})
})
.then((response) => response.json())
.then((responseJson) => {
readComments(sel_board, dispatch);
})
.catch((error) => {
console.error(error);
});
},
onUserChange: (sel_user) => {
dispatch(select_user(sel_user));
}
}
}
const readComments = (board_id, dispatch) => {
fetch(‘http://’ + HOST_ADDR + ‘/board/readComments/’ + board_id)
.then((response) => response.json())
.then((responseJson) => {
dispatch(comments_read(responseJson.rows));
})
.catch((error) => {
console.error(error);
});
}
const CCommentAdd = connect(mapStateToProps, mapDispatchToProps)(CommentAdd);
export default CCommentAdd;
[/bash]
rnative/components/CommentAdd.js
[bash]
import React from “react”;
import {
StyleSheet,
Text,
TextInput,
View,
ListView,
Button,
Picker
} from ‘react-native’;
const CommentAdd = ({sel_board, users, current_token, sel_user, onCommentPost,onUserChange}) => {
let inpText;
let items = [];
const Item = Picker.Item;
users.map((u) => {
items.push( );
})
return (
inpText = text}
/>
{
onUserChange(val);
}}>
{items}
{
onCommentPost(sel_board, sel_user , inpText, current_token);
}}
title=”投稿” />
)
}
const styles = StyleSheet.create({
row:{
flex: 1,
flexDirection: “row”
},
comment: {
width: 400
},
picker: {
flex: 3,
},
btn: {
flex:2
},
});
export default CommentAdd;
[/bash]
動作確認
起動して、掲示板をどれか選択してみてください。
以下のようなページが表示されます。
投稿欄に何か文字を入力し、Pickerから投稿ユーザーを選択し(これ必ずやってください(バグですが・・・))
投稿ボタンを押してみてください。
ちゃんと投稿できたら、成功です。
[bash]
$ react-native run-android
[/bash]
長くなりましたが、これで終了です。
GitHubの公開ソースの利用の仕方
ここで公開したソースはすべてGitHubに公開しています。ご自由にご利用ください。
APIサービス(バックエンド)
https://github.com/h-mito/reactnative_rails_board
ReactNativeアプリ(フロントエンド)
https://github.com/h-mito/reactnative_board
利用方法は以下となります。
[bash]
$ cd
$ mkdir workspace
$ cd workspace
$ mkdir reactnative_board_app
$ cd reactnative_board_app/
$ git clone https://github.com/h-mito/reactnative_rails_board
$ git clone https://github.com/h-mito/reactnative_board
$ cd reactnative_rails_board
$ bundle install
$ rake db:migrate
$ rake db:seed
$ rails s -b 0.0.0.0
[/bash]
別ターミナルを開いて
[/bash]
[bash]
$ cd
$ cd workspace/reactnative_board_app/reactnative_board/
$ npm install
$ nano constants/index.js
[/bash]
ご自身の開発マシンのIPアドレスに書き換える
[bash]
export const HOST_ADDR=’192.168.11.6:3000′;
[/bash]
Android Studioの起動、AVD Manager起動、仮想デバイス起動
別ターミナルを開いて
[bash]
$ /opt/android-studio/bin/studio.sh
[/bash]
メニューより Tools >> Android >> AVD Manager を起動
仮想デバイスを実行(Andoridのエミュレーター画面が表示されます。)
[bash]
$ cd
$ cd workspace/reactnative_board_app/reactnative_board/
$ react-native start > /dev/null 2>&1 &
$ react-native run-android
[/bash]
掲示板一覧が表示され、いずれかの掲示板を選択すると
以下のような画面が出ればOK。
Leave a comment