Last active
January 22, 2019 05:03
-
-
Save fumiyasac/54f5233904bde5e7cac4140d2a828cef to your computer and use it in GitHub Desktop.
ReactNative+Redux+NativeBaseでつくるサンプル実装をのぞく ref: https://qiita.com/fumiyasac@github/items/e27a5901dde1dbcb2086
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
// React-Reduxのインポート宣言 → ProviderタグでラップすることでReactコンポーネント内でStoreにアクセスできるようにする | |
import { Provider } from 'react-redux'; | |
// createStore, applyMiddlewareのインポート宣言 | |
import { createStore, applyMiddleware } from 'redux'; | |
// redux-thunkのインポート宣言 | |
import ReduxThunk from 'redux-thunk'; | |
// redux-loggerのインポート宣言 | |
import logger from 'redux-logger'; | |
// react-native-router-fluxのインポート宣言(Router, Sceneを使用) | |
import { Router, Scene } from 'react-native-router-flux'; | |
// reducerのインポート宣言 | |
import reducers from './redux/reducers'; | |
// configのインポート宣言 ※config/index.jsを作成し下記を定義(Firebaseから持ってくる値) | |
/** | |
* (補足) | |
* ※下記のようにご自身のFirebaseの設定を行なってください | |
* export const API_KEY = '●●●'; | |
* export const AUTH_DOMAIN = '●●●'; | |
* export const DATABASE_URL = '●●●; | |
* export const STORAGE_BUCKET = '●●●'; | |
* export const MESSAGING_SENDER_ID = '●●●'; | |
*/ | |
import { | |
API_KEY, | |
AUTH_DOMAIN, | |
DATABASE_URL, | |
STORAGE_BUCKET, | |
MESSAGING_SENDER_ID | |
} from './config'; | |
// 各画面表示用のそれぞれのコンポーネント | |
import TutorialContents from './components/contents/TutorialContents'; | |
import AuthContents from './components/contents/AuthContents'; | |
import GlobalTabContents from './components/contents/GlobalTabContents'; | |
import RecordRequestContents from './components/contents/RecordRequestContents'; | |
import SettingContents from './components/contents/SettingContents'; | |
import WebViewContents from './components/contents/WebViewContents'; | |
export default class App extends React.Component { | |
// - Component Life Cycles | |
// コンストラクタ | |
/** | |
* (補足) | |
* v0.54.2ではFirebaseの読み込みに関する処理は`componentWillMount()`で行なっていたが、v0.57.8ではコンストラクタで行う。 ※Firebaseのrequireに関する処理もこの中で実行する。 | |
*/ | |
constructor(props) { | |
super(props) | |
// firebaseのインポート宣言を行う | |
const firebase = require("firebase"); | |
// firebaseのセッティング情報を記載する | |
// ※API情報に関してFirebaseコンソールを取得 → Authentication → 「ログイン方法」でメール/パスワードを有効にする | |
const config = { | |
apiKey: API_KEY, | |
authDomain: AUTH_DOMAIN, | |
databaseURL: DATABASE_URL, | |
storageBucket: STORAGE_BUCKET, | |
messagingSenderId: MESSAGING_SENDER_ID | |
}; | |
// firebaseを有効にする | |
firebase.initializeApp(config); | |
} | |
// - Rendering Components | |
render() { | |
// Redux本来のdispatch処理が実行される前にMiddlewareの処理を実行する | |
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk, logger)); | |
return ( | |
<Provider store={store}> | |
<Router> | |
{/* | |
(補足) | |
ライブラリ「React Native Router Flux」記載箇所の変更点 | |
`root`となるタグ部分にも`hideNavBar={true}`の記載を追加する | |
※ このサンプルではヘッダーのナビゲーション部分は各画面ごとにヘッダー部品を適用 | |
*/} | |
<Scene key="root" hideNavBar={true}> | |
<Scene key="auth"> | |
<Scene key="TutorialContents" initial={true} component={TutorialContents} hideNavBar={true} /> | |
<Scene key="AuthContents" component={AuthContents} hideNavBar={true} /> | |
</Scene> | |
<Scene key="main"> | |
<Scene key="GlobalTabContents" initial={true} component={GlobalTabContents} hideNavBar={true} /> | |
<Scene key="RecordRequestContents" component={RecordRequestContents} hideNavBar={true} /> | |
<Scene key="SettingContents" component={SettingContents} hideNavBar={true} /> | |
<Scene key="WebViewContents" component={WebViewContents} hideNavBar={true} /> | |
</Scene> | |
</Scene> | |
</Router> | |
</Provider> | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { | |
Form | |
} from 'native-base'; | |
・・・(省略)・・・ | |
// 認証コンテンツ用の共通コンポーネント | |
import AuthFormInputMail from './AuthFormInputMail'; | |
import AuthFormInputPassword from './AuthFormInputPassword'; | |
import AuthFormErrorMessage from './AuthFormErrorMessage'; | |
・・・(フォーム用の部品に関するComponentを予め切り出しておきインポートする)・・・ | |
class AuthForm extends React.Component { | |
// - Functions | |
// メールアドレスの入力値変更時の処理 | |
_onMailChange = (text) => { | |
// TODO: 入力したメールアドレスを一時的に保存するstateの変更を行う | |
}; | |
・・・(フォーム用の部品の動きと連動して実行する処理があれば記載する)・・・ | |
// - Rendering Components | |
render() { | |
return ( | |
<Form> | |
<AuthFormInputMail value={this.props.mail} onChangeText={ (mail) => this._onMailChange(mail) } /> | |
{/* | |
// TODO: このComponentのStateの変化に応じてボタンの状態やエラーメッセージの状態を反映する | |
*/} | |
</Form> | |
); | |
}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { | |
StyleSheet | |
} from 'react-native'; | |
import { | |
Item, | |
Input, | |
Label | |
} from 'native-base'; | |
export default class AuthFormInputMail extends React.Component { | |
// - Rendering Components | |
render() { | |
const { value, onChangeText } = this.props; | |
return ( | |
<Item stackedLabel> | |
<Label style={styles.title}>メールアドレス:</Label> | |
<Input | |
style={styles.input} | |
value={value} | |
placeholder="例)[email protected]" | |
onChangeText={onChangeText} | |
/> | |
</Item> | |
); | |
}; | |
} | |
// - Component Styles | |
const styles = StyleSheet.create({ | |
title: { | |
fontSize: 13, | |
fontWeight: "bold", | |
color: "#333333" | |
}, | |
input: { | |
fontSize: 13, | |
color: "#666666" | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1. 下記のような画面のルーティングをApp.jsなどに定義する | |
<Router> | |
<Scene key="root"> | |
<Scene key="main"> | |
<Scene key="ComponetA" component={ComponetA} initial={true} /> | |
<Scene key="ComponetB" component={ComponetB} /> | |
</Scene> | |
</Scene> | |
</Router> | |
※ 一番最初に表示されるのはComponetAとなる。 | |
2. 遷移元からComponentBへ進む | |
・遷移先のComponentへ送る値がある場合 → Actions.ComponetB({ id: item.id, title: item.title, content: item.content }); | |
・遷移先のComponentへ送る値がない場合 → Actions.ComponetB(); | |
※ 送った値は該当のComponentBのthis.propsに格納された状態になる | |
3. ComponentBから遷移元へ戻る | |
Actions.pop(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { | |
StyleSheet | |
} from 'react-native'; | |
import { | |
Header, | |
Left, | |
Right, | |
Body, | |
Title, | |
Button, | |
Icon | |
} from 'native-base'; | |
export default class GlobalHeader extends React.Component { | |
// - Rendering Components | |
render() { | |
const { title, onPressMenuButton, onPressSettingButton } = this.props; | |
return ( | |
<Header iosBarStyle="light-content" style={styles.headerBackgroundColor} hasTabs> | |
<Left> | |
<Button transparent onPress={onPressMenuButton}> | |
<Icon style={styles.buttonColor} name="menu" /> | |
</Button> | |
</Left> | |
<Body> | |
<Title style={styles.titleColor}>{title}</Title> | |
</Body> | |
<Right> | |
<Button transparent onPress={onPressSettingButton}> | |
<Icon style={styles.buttonColor} name="settings" /> | |
</Button> | |
</Right> | |
</Header> | |
); | |
}; | |
} | |
// - Component Styles | |
const styles = StyleSheet.create({ | |
headerBackgroundColor: { | |
backgroundColor: '#4169e1' | |
}, | |
titleColor: { | |
color: '#ffffff' | |
}, | |
buttonColor: { | |
color: '#ffffff' | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { | |
Platform, | |
StyleSheet | |
} from 'react-native'; | |
import { | |
Button, | |
Icon, | |
Text | |
} from 'native-base'; | |
export default class GlobalTab extends React.Component { | |
// - Rendering Components | |
render() { | |
const { selected, icon, title } = this.props; | |
let deviceStyle = (Platform.OS === "ios") ? iosStyles : androidStyles; | |
return ( | |
<Button vertical onPress={this.props.onPress}> | |
<Icon style={selected ? deviceStyle.tabSelectedColor : deviceStyle.tabDefaultColor} name={icon} /> | |
<Text style={selected ? deviceStyle.tabSelectedColor : deviceStyle.tabDefaultColor}>{title}</Text> | |
</Button> | |
); | |
}; | |
} | |
// - Component Styles | |
const iosStyles = StyleSheet.create({ | |
tabDefaultColor: { | |
color: '#999999', | |
}, | |
tabSelectedColor: { | |
color: '#4169e1' | |
} | |
}); | |
const androidStyles = StyleSheet.create({ | |
tabDefaultColor: { | |
color: '#c6c6c6', | |
}, | |
tabSelectedColor: { | |
color: '#ffffff' | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
・・・(省略)・・・ | |
import GlobalFooter from '../common/GlobalFooter'; | |
import GlobalTab from '../common/GlobalTab'; | |
・・・(省略)・・・ | |
// タブ表示用の要素 | |
let screenItems = [ | |
// タブと連動した部分 | |
{ screen: "feed", title: "フィード", icon: "list" }, | |
{ screen: "diary", title: "勉強日記", icon: "clipboard" }, | |
・・・(他にもフッターに並べたいものがあれば同様に追加していく)・・・ | |
]; | |
export default class GlobalTabContents extends React.Component { | |
// - Component Life Cycles | |
// コンストラクタ | |
constructor(props) { | |
super(props); | |
// ステートの初期化を行う(ドロワーに関する設定と現在選択されている画面に関する設定) | |
this.state = { isDrawerOpen: false, isDrawerDisabled: false, selectedIndex: 0 }; | |
}; | |
// - Functions | |
・・・(省略)・・・ | |
// タブのボタンを表示する | |
_showGlobalTabs = () => { | |
return screenItems.map( (tabBarItem, index) => { | |
return ( | |
<GlobalTab | |
key={index} | |
selected={this.state.selectedIndex === index} | |
title={tabBarItem.title} | |
icon={tabBarItem.icon} | |
onPress={ () => this._onPressGlobalTab(index) } /> | |
); | |
}); | |
}; | |
// タブのボタンを押下した際の処理 | |
_onPressGlobalTab = (index) => { | |
this.setState({ selectedIndex: index }); | |
}; | |
・・・(省略)・・・ | |
// - Rendering Components | |
render() { | |
const { selectedIndex, isDrawerDisabled } = this.state; | |
return ( | |
{/* 必要なボタン要素を配置する関数を渡す */} | |
<GlobalFooter tabs={this._showGlobalTabs()} /> | |
); | |
}; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// combineReducersの処理を行うためのインポート宣言 | |
import { combineReducers } from 'redux'; | |
//各々の要素に関するReducerのインポート宣言 | |
// → AuthReducer: 認証処理に関するState処理に関するReducer | |
// → NewsReducer: 最新のお知らせの取得処理に関するState処理に関するReducer | |
// → FeedReducer: フィード情報の取得処理に関するState処理に関するReducer | |
// → RecordReducer: 記録データ情報の取得処理に関するState処理に関するReducer | |
// → RecordFormReducer: 記録データのフォーム処理に関するState処理に関するReducer | |
import AuthReducer from './AuthReducer'; | |
import NewsReducer from './NewsReducer'; | |
import FeedReducer from './FeedReducer'; | |
import RecordReducer from './RecordReducer'; | |
import RecordFormReducer from './RecordFormReducer'; | |
// それぞれのReducerを集約して一つのStateとして管理する | |
export default combineReducers({ | |
auth: AuthReducer, | |
feed: FeedReducer, | |
news: NewsReducer, | |
records: RecordReducer, | |
recordForm: RecordFormReducer | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 最新のお知らせ情報のAction定義のインポート宣言 | |
import { | |
NEWS_FETCH, | |
NEWS_FETCH_SUCCESS, | |
NEWS_FETCH_FAILURE | |
} from '../actions/types'; | |
// 初期状態のステート定義(オブジェクトの形にする) | |
const initialState = { newsList: null, error: '', loading: false }; | |
// MARK: - Functions | |
// 選択されたケースを元にstateの更新を行うメソッド | |
export default (state = initialState, action) => { | |
switch (action.type) { | |
case NEWS_FETCH: | |
return { ...state, ...initialState, loading: true }; | |
case NEWS_FETCH_SUCCESS: | |
return { ...state, ...initialState, newsList: action.payload }; | |
case NEWS_FETCH_FAILURE: | |
return { ...state, error: '新着お知らせの取得に失敗しました。', loading: false }; | |
default: | |
return state; | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { | |
StyleSheet | |
} from 'react-native'; | |
import { | |
Content | |
} from 'native-base'; | |
// connectのインポート宣言を行う | |
import { connect } from 'react-redux'; | |
// ActionCreator(Actionの寄せ集め)のインポート宣言(this.props.この中に定義したメソッド名の形で実行) | |
import { | |
getAllNews | |
} from '../../../../../redux/actions'; | |
// 新着のお知らせコンテンツ用の共通コンポーネント | |
import NewsListItem from './NewsListItem'; | |
import NewsListLoading from './NewsListLoading'; | |
import NewsListError from './NewsListError'; | |
class NewsList extends React.Component { | |
// - Component Life Cycles | |
// コンポーネントの内容がMountされる前に行う処理 | |
componentWillMount() { | |
this.props.getAllNews(); | |
} | |
// - Functions | |
// 再度取得する処理 | |
_onPressRetryButton = () => { | |
this.props.getAllNews(); | |
}; | |
// 取得した最新のお知らせを表示する処理 | |
_displayNewsList = () => { | |
const { newsList, error, loading } = this.props; | |
// 最新のお知らせが取得中の場合における表示 | |
if (loading) { | |
return ( | |
<NewsListLoading /> | |
); | |
} | |
// 最新のお知らせが取得失敗の場合における表示 | |
if (error !== '') { | |
return ( | |
<NewsListError | |
error={error} | |
onPressRetryButton={ () => this._onPressRetryButton() } /> | |
); | |
} | |
// 最新のお知らせ情報を配列に格納し直す | |
var newsItems = []; | |
for (let index in newsList) { | |
newsItems.push(newsList[index]); | |
} | |
// 最新のお知らせのリストを生成して表示する | |
return newsItems.map( (item, index) => { | |
return ( | |
<NewsListItem key={index} item={item} /> | |
); | |
}); | |
}; | |
// MARK: - Rendering Components | |
render() { | |
return ( | |
<Content style={styles.container}> | |
{this._displayNewsList()} | |
</Content> | |
); | |
}; | |
} | |
// - Component Styles | |
const styles = StyleSheet.create({ | |
container: { | |
flex: 1, | |
backgroundColor: '#ffffff' | |
} | |
}); | |
// newのStateから値を取得してthis.propsにセットする ※取得したいStateについては上記のReducerを参照 | |
const mapStateToProps = ({ news }) => { | |
// 引数で受け取った認証データを変数に分解する | |
const { newsList, error, loading } = news; | |
// 分解したそれぞれの値をオブジェクトにして返却する | |
return { newsList, error, loading }; | |
}; | |
// インポート可能にする宣言 | |
export default connect(mapStateToProps, { getAllNews })(NewsList); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"jest": { | |
"preset": "react-native", | |
"transformIgnorePatterns": [ | |
"/node_modules/(?!native-base|react-native-router-flux)/" | |
] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { | |
StyleSheet | |
} from 'react-native'; | |
import { | |
Content | |
} from 'native-base'; | |
// 設定コンテンツ用の共通コンポーネント | |
import SettingListItem from './SettingListItem'; | |
export default class SettingList extends React.Component { | |
// MARK: - Functions | |
// 取得した設定コンテンツ用データを表示する処理 | |
_displaySettingList = () => { | |
const { settingItems } = this.props; | |
// 設定コンテンツ用データのリストを生成して表示する | |
{/* | |
(補足) 設定コンテンツのリストの形式はこんな感じになっている | |
let settingItems = { | |
"items": [ | |
{ title: "Twitter", onPressListItem: () => _goTwitterPage() }, | |
{ title: "Facebook", onPressListItem: () => _goFacebookPage() }, | |
{ title: "Github", onPressListItem: () => _goGithubPage() }, | |
{ title: "Slideshare", onPressListItem: () => _goSlidesharePage() }, | |
{ title: "Qiita", onPressListItem: () => _goQiitaPage()) }, | |
] | |
}; | |
*/} | |
return settingItems.items.map( (item, index) => { | |
return ( | |
<SettingListItem | |
key={index} | |
title={item.title} | |
onPressListItem={item.onPressListItem} /> | |
); | |
}); | |
}; | |
// - Rendering Components | |
render() { | |
const { settingItems } = this.props; | |
return ( | |
<Content style={styles.container}> | |
{this._displaySettingList()} | |
</Content> | |
); | |
}; | |
} | |
// - Component Styles | |
const styles = StyleSheet.create({ | |
container: { | |
flex: 1, | |
backgroundColor: '#ffffff' | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { | |
StyleSheet | |
} from 'react-native'; | |
import { | |
Text, | |
Icon, | |
ListItem | |
} from 'native-base'; | |
export default class SettingListItem extends React.Component { | |
// - Functions | |
// それぞれのソーシャルリンクに合わせた色を設定する | |
_getSocialMediaColorCode = (title) => { | |
switch (title) { | |
case "Twitter": | |
return colorStyles.twitterColor; | |
case "Facebook": | |
return colorStyles.facebookColor; | |
case "Github": | |
return colorStyles.githubColor; | |
case "Slideshare": | |
return colorStyles.slideshareColor; | |
case "Qiita": | |
return colorStyles.qiitaColor; | |
default: | |
return colorStyles.defaultColor; | |
} | |
}; | |
// - Rendering Components | |
render() { | |
const { title, onPressListItem } = this.props; | |
return ( | |
<ListItem style={styles.listItem} onPress={onPressListItem}> | |
<Icon style={[styles.listItemIcon, this._getSocialMediaColorCode(title)]} name="paper-plane" /> | |
<Text style={styles.listItemText}>{title}</Text> | |
</ListItem> | |
); | |
}; | |
} | |
// MARK: - Component Styles | |
const styles = StyleSheet.create({ | |
listItem: { | |
height: 50 | |
}, | |
listItemIcon: { | |
fontSize: 16, | |
}, | |
listItemText: { | |
fontSize: 13, | |
paddingLeft: 8, | |
fontWeight: 'normal', | |
color: '#555555' | |
} | |
}); | |
const colorStyles = StyleSheet.create({ | |
twitterColor: { | |
color: '#00aced', | |
}, | |
facebookColor: { | |
color: '#3b5998', | |
}, | |
githubColor: { | |
color: '#333333', | |
}, | |
slideshareColor: { | |
color: '#0077b5', | |
}, | |
qiitaColor: { | |
color: '#55c500', | |
}, | |
defaultColor: { | |
color: '#888888', | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
・・・(その他の発行したいアクションについても同様に定義をしています)・・・ | |
// 新着お知らせの取得&表示処理に関するActionの定義 | |
export const NEWS_FETCH = 'news_fetch'; | |
export const NEWS_FETCH_SUCCESS = 'news_fetch_success'; | |
export const NEWS_FETCH_FAILURE = 'news_fetch_failure'; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment