アプリがすぐに作れる!React Native(expo) + Rails API(devise token auth)のサンプルコード
更新内容:8/2
下記2点の機能を追加しました!
・画像アップロード機能
・ドラッグダウンで最新の情報を取得する機能
※注意点です
Railsは動作検証できておりますが、React NativeはiOSのみ検証が済んでいます。Androidの確認はもう少し後になるので、Androidの検証も済んでからが良い、という方は購入をしばらくお待ちください。
Rails(devise token auth)とReact Nativeの記事が少なく結構苦労したので、
連結部分とCRUDのやりとり部分を作成して他のプロジェクトに使えるようにしてみました。
まだドキュメントが整理されていないので、ソースコード料として2,000円で販売していますが、ドキュメントが出来上がったら4,000円ぐらいで販売する予定です。
React以外のAngularやVueを扱っている人であればソースコードは問題なく読めると思うので、安いうちに購入をお勧めします!
概要
アプリの概要動画↑
イベントアプリ情報を掲載できる掲示板のようなシンプルなアプリで、
devise token authをベースとした認証機能とCRUD対応しています
このサンプルコードを使うことで、
・CRUD
・APIとの連携方法の調査
など土台に利用することができます
実際に私はこのベースを使って別のプロジェクトに応用しているので
これをそのまま使うのではなく、reduxや認証機能など
使いまわせるところは使い回す、というのがお勧めです!
ソースコードの簡単な説明
こちら一部のファイルを抜粋しています。
特にclientはどのように実装されているか不安だと思いますので
いくつかご提示しています。
また、RailsもGemfileを公開しています。
clientのファイル構成
・components→再利用する可能性がある機能
・redux→redux関連の機能
・screens→それぞれ画面を作成する機能
・shared→apiのリンクやCRUDのメソッドをまとめている
・router.js→ルーティング設定
個人的にはこのアーキテクチャーが一番価値があるのではないか?と思ってます
こちらは具体的なコードのサンプルです
classかfunctionかでかなり悩みましたが、
最近はclassではなくfunctionで実装すること流れになっているようなので、
functionで実装を進めました。
classからfunctionへ流れている理由はコードが冗長になってしまうことが原因のようです。
ちなみにコードですが、
できる限り同じスタイルで実装することを心掛けました
なので、一つ理解できれば、全てのファイルを読むことができるようになるかと思います
import React, { useState } from 'react';
import { ActivityIndicator, StyleSheet, Button as ReactNativeButton } from 'react-native';
import { Container, Header, Button, Text, Content, Form, Item, Input, Label } from 'native-base';
import { setAuthData, login } from '../shared/auth_service';
import { useDispatch } from 'react-redux';
import { addCurrentUser } from '../redux/actions/current_user';
import { Ionicons, MaterialIcons } from '@expo/vector-icons';
export default function LoginScreen(props) {
const dispatch = useDispatch();
// 必要な変数を定義
const [isLoading, setIsLoading] = useState(false);
const [isFailed, setIsFailed] = useState(false);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onSubmit = () => {
setIsLoading(true);
return (
login(email, password)
.then(response => {
setIsLoading(false);
const token = response.headers['access-token'];
const client = response.headers['client'];
const uid = response.headers['uid'];
if (token && client && uid) {
// userのログイン情報をreduxで管理
dispatch(addCurrentUser(response.data.data))
// storageにtoken情報などを追加
setAuthData(token, client, uid);
setIsFailed(false);
props.navigation.navigate('Home');
} else {
setIsFailed(true);
}
}).catch(data => {
setIsLoading(false);
})
);
}
const loginButton = () => {
if (isLoading) {
return <ActivityIndicator size='small'/>;
} else {
return (
<Button style={ styles.button } onPress={ () => onSubmit() }>
<Text style={ styles.text }>ログイン</Text>
</Button>
)
}
}
return (
<Container>
<Header/>
<Content style={ styles.main }>
{ isFailed && <Text>ログインに失敗しました。</Text> }
<Form>
<Item inlineLabel>
<MaterialIcons name='email' style={ styles.icon } size={ 24 } color='black'/>
<Input placeholder='Email' onChangeText={ (email) => setEmail(email) }/>
</Item>
<Item inlineLabel last>
<Ionicons name='md-key' style={ styles.icon } size={24} color='black' />
<Input
placeholder='パスワード'
secureTextEntry={ true }
onChangeText={ (password) => setPassword(password) }/>
</Item>
</Form>
{ loginButton() }
<ReactNativeButton title='会員登録する' onPress={ () => props.navigation.navigate('Signup') }/>
</Content>
</Container>
);
}
const styles = StyleSheet.create({
icon: {
marginRight: 10
},
main: {
height: '90%',
backgroundColor: '#eee',
},
textInput: {
height: 60,
width: 300,
paddingLeft: 20,
margin: 10,
borderWidth: 1,
borderRadius: 8,
},
button: {
margin: 30
},
text: {
marginLeft: 'auto',
marginRight: 'auto',
marginTop: 'auto',
marginBottom: 'auto',
}
});
ちなみにこちらはAPIとの連結部分
Promiseオブジェクト作成しているので、screensで読んでthenを使ったりできます
export async function findAll() {
const config = await getAuthorization();
return await axios.get(`${ apiPath }events`, config);
}
export async function save(title, body, address) {
const config = await getAuthorization();
const event = { title: title, body: body, address: address };
return await axios.post(`${ apiPath }events/`, { event }, config);
}
次はAPIサーバーです
非常にシンプルなJSON APIです。こちらは特に触るところはなく、機能を追加する際の参考にしてください
module Api
class EventsController < ApplicationController
before_action :authenticate_api_user!
before_action :set_event, only: %i[show update destroy]
def index
begin
response_success(Event.all.map{ |event| event.to_dict })
end
rescue StandardError => e
logger.error e.message
response_bad_request
end
def show
begin
response_success(@event.to_dict)
end
rescue StandardError => e
logger.error e.message
response_bad_request
end
・・・・・
Gemfile
devise token authをベースとしてAPIサーバーを作るためのgemを入れています
rspecも記述しているので、APIサーバーのテストの書き方の参考にしてください
# frozen_string_literal: true
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.6.3'
gem 'rails', '~> 6.0.3', '>= 6.0.3.1'
gem 'puma', '~> 4.1'
gem 'bootsnap', '>= 1.4.2', require: false
gem 'jbuilder', '~> 2.7'
group :development, :test do
gem 'dotenv-rails'
gem 'rspec-rails', '~> 3.6.0'
gem 'factory_bot_rails', '~> 4.10.0'
gem 'ffaker'
gem 'pry-rails'
gem 'pry-remote'
gem 'brakeman', '~> 4.7', require: false
gem 'rails_best_practices', '~> 1.19', require: false
gem 'rubocop', '~> 0.76', require: false
gem 'rubocop-rails', '~> 2.3', require: false
gem 'sqlite3', '~> 1.4'
gem 'byebug', platforms: %i[mri mingw x64_mingw]
end
group :development do
gem 'letter_opener'
gem 'letter_opener_web'
gem 'better_errors'
gem 'rails-erd'
gem 'listen', '~> 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
group :production do
gem 'pg'
end
gem 'devise'
gem 'devise_token_auth'
gem 'rack-cors'
gem 'jp_prefecture' # イベントページに使う予定ですが、まだ使ってません
gem 'enumerize' # こちらもまだ使っていません
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
起動方法
React Native:
$ npm install
$ npm start
でexpoの起動画面が開くので、iOSで実行します
実行するとエミュレーターが起動します
※起動時はコンパイルに時間がかかる可能性が高いです
Rails:
$ bundle install
$ yarn install
$ rails db:migrate
$ rails s -p 3001
Railsは特に設定などないためこれで問題ないかと思います。
※開発で利用したsqliteもソースコードに入っています
ソースコード
githubに招待することも考えましたが、購入後に招待だと遅いので
noteにzip形式で掲載することにしました
ここから先は
¥ 2,000
この記事が気に入ったらサポートをしてみませんか?