はじめに
よくよく考えると今日クリスマスイブらしいですが、残念ながら記事書くぐらいには予定がないです!
クリスマスの高円寺は逆にとても空いているのでオススメですよ!
色々と進捗あって【React Native】良さげなコンポーネント紹介が古くなってしまったのでそれ以降変更あったり、新しいやつみつけてたりするので改めての報告です。
去年と同じものを紹介したりしてますが、それはとても良かったり、情勢に変化があったパターンは紹介しています!
僕もまだまだ知識浅いのでこっちだぜ!これもあるよ!などあればお教えいただけますと幸いです!
今年は僕がこの記事を書いた地点のスター数を記載しています!
ルーティング
react-native-router-flux ★:6048
バージョン追えていない感と進んでいない感が半端なくなってきた頃合いですが、色々と触ってみた感じ、(動く環境なら)一番ちゃんと動くんじゃないかなと個人的には思っています。
今使っている人は、動いているのなら無理に置き換える必要がないかなと思いますが、今から作るとなるとなんとも言えない感じあります。
import {Scene, Router} from 'react-native-router-flux';
class App extends React.Component {
render() {
return <Router>
<Scene key="root">
<Scene key="login" component={Login} title="Login"/>
<Scene key="register" component={Register} title="Register"/>
<Scene key="home" component={Home}/>
</Scene>
</Router>
}
}
こんな感じの実装。
React Native Router Fluxを使ってみませんか・・・?という記事も書きました。
ということもあったんですが、僕が新しくプロジェクトを率いることになった頃に、V4になってReact NavigationのAPIを利用する弟子入りを果たし、mobxよりになったので、本家つかうかということで僕はReact Navigationを使い始めました。
しかし、こいつはこいつで未だにかなり筋がいいなと思う毎日。結局reduxを使っている会社でもこれを使っていて楽しそうにしているところを指をくわえながら見ています。
V4になってもあまり使い方が変わらずとても素晴らしいなと思います。このルーティングライブラリが素晴らしいのは圧倒的かつ直感的な使いやすさにあると思います。
import { Actions } from 'react-native-router-flux'
// navigate to 'home' as defined in your top-level router
Actions.home(PARAMS)
// go back (i.e. pop the current screen off the nav stack)
Actions.pop()
このような感じで実装されます。Actionsについてはシングルトンインスタンスのような存在で、このようにして利用します。
例えばhomeと名付けられた画面に遷移したい場合はActions.home()
で、戻りたくばActions.pop()
で。さらには、ActionConstという神がかった便利機能で次の画面に行きつつ履歴を削除や、履歴にいまから遷移しようとしている場所があればそこに戻るしなければ画面遷移、といった具合に調整できます。
ドキュメント的に未だに闇を抱えていそうな雰囲気があるのですが、それでもかなり楽できるだろうと思いますし、ルーティングコードも見やすくなりそうです。
react-navigation ★:8653
公式の推し。
まだ微妙になんとかなってくれーーーという感じのバグが残っていてこれ使えば間違いないと言える感じではないと気がします。
僕が触った時には stack -> tab&stack -> stack と遷移する画面を作った時にはナビゲーションが重複するといったバグがありました。他にはAPIが少なかったりとしてますが、今後は盛り上がって行くと思われます(責任はとらないですが)!。
const MainScreenNavigator = TabNavigator({
Recent: { screen: RecentChatsScreen },
All: { screen: AllContactsScreen },
});
こんな感じの実装になります。
これがrnrfのルーティングに相当する感じです!
しかしこれがなかなかに曲者でプロダクションで使って見たところかなりやりにくいなと感じました。もっと時間があったら色々検討したんですが、開発時期と納期が絶妙で、安パイぽいこれを選んでしまったことは失敗だったと感じています・・・・。決してこれがクソというわけではなく、スピードある開発だったり、僕のようなへっぽこぴーが使う分にはちょっとむずかしいかなぁって思います。現状rnrfもこの子のAPIを使うようになっているので選択肢としてはありだけど、もうちょっと便利な機能を最初から用意してくれていた方が助かる的な感じですね。ご新規さんウェルカムキャンペーンみたいな初心者応援のないネトゲみたいな感じです。
const AllContactsScreen = StackNavigator({
・・・
});
const MainScreenNavigator = TabNavigator({
Recent: { screen: RecentChatsScreen },
All: { screen: AllContactsScreen },
});
こんな感じに階層が深くなっていくので見づらい感がかなりあります。
それと画面遷移については
this.props.navigation.navigate('Profile')}
こんな塩梅で動作します。
しかし、すごくシンプルなため、rnrfにはあったけどもこっちにはない機能がたくさんあり、自分でなんとかする必要が結構あります。
ただ
https://reactnavigation.org/docs/routers/api
こんな感じで拡張性の高いAPIが簡単に使えたりするので、おそらく腕の立つエンジニアからするとこちらの方が良いのかもしれません・・・!!
react-router-native ★:? (react-router: 27058)
monoreposになってしまい、盛り上がりがよくわからなくなってきた。v2がわかりやすくてよかったのでV4はちゃんとさわったわけではないのですが、個人的に応援したい枠なので紹介させてください。
現状、○ンダムフレームのように眠っている状態。experimentalに入っているstackRouterが復活してくれればワンチャンある気がします・・・。
画面遷移はこのように行って、
<Link replace={true} to={`${match.url}/${thing.path}`} underlayColor="#f0f0f0">
<Text style={{ padding: 15, paddingLeft: 0 }}>{thing.label}</Text>
</Link>
ルーティングはこのように行います。
const App = () => (
<NativeRouter>
<View style={{ flex: 1, marginTop: 20 }}>
<Route path="/" exact render={() => <Redirect to="/home"/>}/>
<TabRoutes>
<TabRoute path="/home"
renderContent={(props) => (
<RecursiveItem rootPath="/home"/>
)}
renderTab={({ isActive }) => (
<Text style={{ color: isActive ? blue : null }}>
Home
</Text>
)}
/>
<TabRoute path="/notifications"
renderContent={(props) => (
<View>
<Text style={{ fontSize: 30 }}>
Notifications
</Text>
</View>
)}
renderTab={({ isActive }) => (
<Text style={{ color: isActive ? blue : null }}>
Notifications
</Text>
)}
/>
<TabRoute path="/messages"
renderContent={(props) => (
<RecursiveItem rootPath="/messages"/>
)}
renderTab={({ isActive }) => (
<Text style={{ color: isActive ? blue : null }}>
Messages
</Text>
)}
/>
</TabRoutes>
</View>
</NativeRouter>
)
結構筋がいいような感じなんですが、気になるのは
import StackRoute from 'react-router-native/experimental/StackRoute'
import { TabRoutes, TabRoute } from 'react-router-native/experimental/TabRoutes'
このexperimentalですね・・・。
これがちゃんと、experimentalでなく正式な機能として提供されるようになってくれたらつかってみようかなぁぐらいの感じです。実際、ちょっとスワイプバックの動きが悪かったりと体調も万全じゃない模様。早く良くなってほしいです。
ネイティブ機能系
react-native-camera ★:4348
カメラ機能使うならこれで問題ないぐらい。
相変わらずこの子は不動の地位を築いています。
写真撮影できるだけかよーって思ったらQRコードもバーコードも読める天才児。
カメラ使うなら本当にこれで良いと思います。
react-native-push-notification ★:2317
プッシュ通知が簡単に実装できます。
若干OSの差分を完全に吸収していない部分があるので両対応させる場合はラッパー的なのを書く必要がありますが、いとも簡単に実装できます。
localpushで使ってみました。
var PushNotification = require('react-native-push-notification');
PushNotification.configure({
// (optional) Called when Token is generated (iOS and Android)
onRegister: function(token) {
console.log( 'TOKEN:', token );
},
// (required) Called when a remote or local notification is opened or received
onNotification: function(notification) {
console.log( 'NOTIFICATION:', notification );
},
// ANDROID ONLY: GCM Sender ID (optional - not required for local notifications, but is need to receive remote push notifications)
senderID: "YOUR GCM SENDER ID",
// IOS ONLY (optional): default: all - Permissions to register.
permissions: {
alert: true,
badge: true,
sound: true
},
popInitialNotification: true,
requestPermissions: true,
});
こんな感じでpush通知受け取った時の動作をかける。
今個人的に悩んでいるのが、push通知受け取った時にアプリ起動した場合、
ios:表示されない
android:表示される
となっているのをなんとかしたいと思ってるんですが、ネイティブ側の知見あんまりなくって困っているのでお教えいただけますと幸いです。
react-native-fcm ★:1102
本当は上で紹介したreact-native-push-notificationで実装しようと思ってたんですが、リモートプッシュの場合って登録とか色々めんどくさかったりするのでこっちを使いました。
とても簡単です!
FCM.on(FCMEvent.Notification, async (notif) => {
// there are two parts of notif. notif.notification contains the notification payload, notif.data contains data payload
if(notif.local_notification){
//this is a local notification
}
if(notif.opened_from_tray){
//iOS: app is open/resumed because user clicked banner
//Android: app is open/resumed because user clicked banner or tapped app icon
}
// await someAsyncCall();
if(Platform.OS ==='ios'){
//optional
//iOS requires developers to call completionHandler to end notification process. If you do not call it your background remote notifications could be throttled, to read more about it see https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application.
//This library handles it for you automatically with default behavior (for remote notification, finish with NoData; for WillPresent, finish depend on "show_in_foreground"). However if you want to return different result, follow the following code to override
//notif._notificationType is available for iOS platfrom
switch(notif._notificationType){
case NotificationType.Remote:
notif.finish(RemoteNotificationResult.NewData) //other types available: RemoteNotificationResult.NewData, RemoteNotificationResult.ResultFailed
break;
case NotificationType.NotificationResponse:
notif.finish();
break;
case NotificationType.WillPresent:
notif.finish(WillPresentNotificationResult.All) //other types available: WillPresentNotificationResult.None
break;
}
}
});
デバイスグループという機能があって、デバイスグループに何台もデバイスを登録することができます。そして、デバイズグループに対してpush通知を送ると登録された全てのデバイスに向けてpush通知が送られます。
これを使うと、1ユーザーが何端末持っていても一つのpush_keyで済むので楽に管理できます。
Firebaseの愚痴になりますが、push通知って怖いのでメールの送信履歴みたいにpush通知も履歴が見れるといいなぁって思います。Firebaseの場合、そもそも登録しているデバイスグループですら見れないので結構困ったりすることがちらほらあります・・・。がデータ閲覧以外はとてもいいのでこれ使っておけばいんじゃないかぁ感があります。
react-native-firebase-analytics ★:425
Firebase アナリティクスをいれれます。Firebaseつかっているならトータルソリューションっぽく使えますね。クラッシュレポートもあるんですが、今日は紹介しません・・・!
Analytics.logEvent('view_item', {
'item_id': 'login'
});
こんな感じで情報をおくれるんですが、Javaちゃんがnullだと十八番のjava.lang.NullPointerException(ぬるぽ)しますので要注意。
基本iOS先につくってって、Androidようのレイアウト修正して、テスト入った時にAndroidだとこうゆう動作すると落ちるとかになったりする原因が結構ぬるぽだったりするので、なんとかしてほしいものである。
react-native-image-picker ★:3214
これがでるあれです。
ImagePicker.showImagePicker(options, (value) => {
onChange(name, {
uri: value.uri,
type: 'image/png',
name: `${name}.png`,
});
});
カメラロール開かせて何かするとかにそういう用途に使えます。
こんな塩梅で画像をアップロードさせられます。
この時、value.uriは画像パスになるので、こいつを使ってあげることでプレビューを表示させたりすることができます。
この画像をアップロードしたい時も、content-typeをmultipartにしてあげて、value.uriを使えばサーバへ値を送信することもできます。
valueの中にはbase64エンコーディングされた文字列も含まれているのでそれを使うのもありなのかもです。
デフォルトのままやっちゃうと、でてくるテキストが英語になるのでちゃんとネイティブの方を直して上げて日本語が出るようにする必要がありまする。
react-native-photo-view ★:425
写真をピンチインで拡大して、ピンチアウトで縮小してくれるやつです。
普通に写真を表示させても、拡大・縮小できないので、「拡大・縮小」する際はこの子を使うとすぐにできます。
<PhotoView
source={{uri: 'https://facebook.github.io/react/img/logo_og.png'}}
minimumZoomScale={0.5}
maximumZoomScale={3}
androidScaleType="center"
onLoad={() => console.log("Image loaded!")}
style={{width: 300, height: 300}} />
こんな感じで実装できます。
ビュー関連
formik★:3984
フロントエンドエンジニアの方が発掘してくれたフォーム管理系のライブラリです。redux-form使ってたんですが、なんか仰々しいし、redux外せなくなるしで、ちょっと悩んでたんですが、この子はシンプルで割と使いやすい気がします。
バリデーションはYupを使っていて、
const Form = Formik({
validationSchema: Yup.object().shape({
...validation.login,
}),
handleSubmit: (values, _p) => {
_p.props.onSubmit(values);
},
})(FormContent);
こんな感じで、HOCをつかいます。バリデーションに引っかかったのであれば、handleSubmitは発火しません。代わりにFormContentがerrorsというオブジェクトを受け取ることになります。このerrorsにはエラー文言が入っていて、あとはフォームにエラーを表示させるだけというわかりやすい仕様。
割と使いやすいのではと思います。
react-native-snap-carousel ★:1550
いとも簡単に、かっこいいカルーセルを作ることができるコンポーネント。
しかも、各画像はFlatListになっている。
v3出たばかりで、console.logのこってたり若干バグあったりするけども、全然問題なく動く気がします。
<Carousel
ref={(c) => { this._carousel = c; }}
data={this.state.entries}
renderItem={this._renderItem}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
/>
こんな感じ。
僕はこれとreact-native-photo-viewをつかって写真が見られる機能を実装しました!
react-native-calendars★:1736
ドキュメントも丁寧で特に困ることなく実装することができました!ロケールも簡単!
<Calendar
// Initially visible month. Default = Date()
current={'2012-03-01'}
// Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
minDate={'2012-05-10'}
// Maximum date that can be selected, dates after maxDate will be grayed out. Default = undefined
maxDate={'2012-05-30'}
// Handler which gets executed on day press. Default = undefined
onDayPress={(day) => {console.log('selected day', day)}}
// Month format in calendar title. Formatting values: http://arshaw.com/xdate/#Formatting
monthFormat={'yyyy MM'}
// Handler which gets executed when visible month changes in calendar. Default = undefined
onMonthChange={(month) => {console.log('month changed', month)}}
// Hide month navigation arrows. Default = false
hideArrows={true}
// Replace default arrows with custom ones (direction can be 'left' or 'right')
renderArrow={(direction) => (<Arrow />)}
// Do not show days of other months in month page. Default = false
hideExtraDays={true}
// If hideArrows=false and hideExtraDays=false do not switch month when tapping on greyed out
// day from another month that is visible in calendar page. Default = false
disableMonthChange={true}
// If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
firstDay={1}
// Hide day names. Default = false
hideDayNames={true}
// Show week numbers to the left. Default = false
showWeekNumbers={true}
/>
こんな感じで色々いじれるので結構幅広いニーズにこたえられると思います。
こんなことや、
こんなことすらできる
という優秀な子です!
react-native-pull-to-refresh ★:102
<PTRView onRefresh={this._refresh} >
<View style={styles.container}>
<Text style={styles.welcome}>
Let's Pull!
</Text>
</View>
</PTRView>
こんなかんじで普通のScrollViewのかわりに使ってonRefreshっていうイベントを設置できるようになる。
公式のやつわかりにくいしめんどくさそうなのでこれを使うと楽勝解決します。
ただ、デフォルトの矢印とかプリローダーは変更できないので、フォークしていい感じに修正して使いました。
react-native-animatable ★:3942
これはアニメーションの決定版です。
去年も紹介しましたが、やはり優秀なのでここでも紹介しています!
なにが良いかというと、React Nativeのアニメーションって結構めんどくさかったりするのですが、これを使うことによってかなり簡単になるほか、上のgifにあるアニメーションにあるアニメーションとはプリセットで存在しているのでさっとできてしまいます。
アニメーションの対象にしたい要素にrefをつけておいて
if (isShow) {
this.ref.transitionTo({ bottom: 0 });
} else {
this.ref.transitionTo({ bottom: -150 });
}
このようにtransitionToでbottom 0と-150のように制御するだけでアニメーションすることができます。
React Native素の状態でかくと
class FadeInView extends React.Component {
state = {
fadeAnim: new Animated.Value(0), // Initial value for opacity: 0
}
componentDidMount() {
Animated.timing( // Animate over time
this.state.fadeAnim, // The animated value to drive
{
toValue: 1, // Animate to opacity: 1 (opaque)
duration: 10000, // Make it take a while
}
).start(); // Starts the animation
}
こんな感じでかかないといけないのでちょっとめんどくさいですが、これを使うとAnimated.Valueの設定なしにできるようになるのが魅力です。
react-native-hyperlink★:180
僕もプロダクションでの実装後に知ってしまってつかっておけばよかったなぁって後悔しています。
このコンポーネントは、
import Hyperlink from 'react-native-hyperlink'
export const defaultLink = () =>
<Hyperlink linkDefault={ true }>
<Text style={ { fontSize: 15 } }>
This text will be parsed to check for clickable strings like https://github.com/obipawan/hyperlink and made clickable.
</Text>
</Hyperlink>
export const regularText = () =>
<Hyperlink onPress={ url => alert(url) }>
<Text style={ { fontSize: 15 } }>
This text will be parsed to check for clickable strings like https://github.com/obipawan/hyperlink and made clickable.
</Text>
</Hyperlink>
export const regularTextLongPress = () =>
<Hyperlink onLongPress={ url => alert(url) }>
<Text style={ { fontSize: 15 } }>
This text will be parsed to check for clickable strings like https://github.com/obipawan/hyperlink and made clickable for long click.
</Text>
</Hyperlink>
export const nestedText = () =>
<Hyperlink onPress={ url => alert(url) }>
<View>
<Text style={ { fontSize: 15 } }>
A nested Text component https://facebook.github.io/react-native/docs/text.html works equally well <Text>with https://github.com/obipawan/hyperlink</Text>
</Text>
</View>
</Hyperlink>
export const highlightText = () =>
<Hyperlink linkStyle={ { color: '#2980b9', fontSize: 20 } }>
<Text style={ { fontSize: 15 } }>
Make clickable strings like https://github.com/obipawan/hyperlink stylable
</Text>
</Hyperlink>
この例の通り中にいれたurlをリンクとして認識して、押した時の挙動などを制御することができます。
サーバからのレスポンステキストを表示させる時に威力を発揮します。
react-native-loading-spinner-overlay★:611
あのぐるぐるを出せるコンポーネントです!
render() {
return (
<View style={{ flex: 1 }}>
<Spinner visible={this.state.visible} textContent={"Loading..."} textStyle={{color: '#FFF'}} />
</View>
);
}
べたで書いておいてもいいかなって思うんですが、毎回こういうのをつくるのもめんどくさいのでこういうものを使っていくとよいかもしれません!
react-native-modalbox ★:1471
モーダルといったらこれ。
各種様々なモーダルを出すことができます。
swipeToClose
をtrueにすることでスワイプで閉じることができるようになります!が「これよくないですか!?スワイプで閉じれるんすよ!!」と作ったものを見せた時に「あ、そんな機能あるんだ」ぐらいにしか言われなかった・・・。
キーボード制御においてAndroidでイマイチうまく動かないバグがあります。あと、React Nativeのalertと併用すると閉じるはずのこいつが閉じなくなる(React Nativeのバグ)があったりします。
<Modal
style={[styles.modal, styles.modal1]}
ref={"modal1"}
swipeToClose={this.state.swipeToClose}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>Basic modal</Text>
<Button onPress={() => this.setState({swipeToClose: !this.state.swipeToClose})} style={styles.btn}>Disable swipeToClose({this.state.swipeToClose ? "true" : "false"})</Button>
</Modal>
react-native-vector-icons ★:6860
かなり説明不要の域に達しているアイコンコンポーネント。
とてもよく使われているので去年も紹介しました、今年も紹介しておきます!
react-native-app-intro ★:1748
こんな感じのアプリをインストールして最初にでてくるイントロダクションの画面を作成できるコンポーンネントです!
return (
<AppIntro>
<View style={[styles.slide,{ backgroundColor: '#fa931d' }]}>
<View level={10}><Text style={styles.text}>Page 1</Text></View>
<View level={15}><Text style={styles.text}>Page 1</Text></View>
<View level={8}><Text style={styles.text}>Page 1</Text></View>
</View>
<View style={[styles.slide, { backgroundColor: '#a4b602' }]}>
<View level={-10}><Text style={styles.text}>Page 2</Text></View>
<View level={5}><Text style={styles.text}>Page 2</Text></View>
<View level={20}><Text style={styles.text}>Page 2</Text></View>
</View>
<View style={[styles.slide,{ backgroundColor: '#fa931d' }]}>
<View level={8}><Text style={styles.text}>Page 3</Text></View>
<View level={0}><Text style={styles.text}>Page 3</Text></View>
<View level={-10}><Text style={styles.text}>Page 3</Text></View>
</View>
<View style={[styles.slide, { backgroundColor: '#a4b602' }]}>
<View level={5}><Text style={styles.text}>Page 4</Text></View>
<View level={10}><Text style={styles.text}>Page 4</Text></View>
<View level={15}><Text style={styles.text}>Page 4</Text></View>
</View>
</AppIntro>
levelでパララックスを調整できます!オシャにするならこれですね。
react-native-code-push★:1748
React Native使うなら使わなきゃ損といわれるCode Pushのライブラリです。
実装コード自体はめちゃめちゃ簡単に書きます。
import codePush from "react-native-code-push";
class MyApp extends Component {
}
MyApp = codePush(MyApp);
設定が色々ややこしいですがそれを乗り越えれば未来があります。
CodePushはjsで書かれた部分をリモートで置き換える機能です。
これをプリローンチ時にやっておくことによって、
- 起動時にリモートのソースをダウンロードしにいく(新しいのがなければ何もしない)
- ダウンロードが完了したのちに、再度起動する
- 新しいソースに入れ替えてアプリを動かす
という動きをすることができます。
バグ対処用ですね!
欠点というか注意点として、
- ダウンロードして初めて起動した際は当然ながら最初のコードが読み込まれる。
- ネイティブコードの差し替えはできない(兆が一ぐらいですが、他のモジュールでネイティブコードのアップデートがあるときとかは要注意かもです)
なので、あくまで急ぎのバグ修正目的に使う感じになります。
リモートソースの読み込みを不可にしたりできるので、リモートのアップロードにしくじった時も素早く対処できます。
が、やはり既存ユーザーに影響があるかもしれないのでアプリの申請時ぐらい緊張します。
NativeBase★:7088
React Native のUIライブラリといったらこれ!
iOS | Android |
---|---|
オシャなコンポーネントがある他、OSのデザイン的な概念に沿うようにいい感じにしてくれます。
fumiyaさんが非常に詳しいので、Native Base関連のtipsはfumiyaさんの記事を参考にすると良いかもしれません!
react-native-elements★:8471
Native Baseの対抗馬!(こっちの方がスター多かった)
こっちもおんなじような感じなので、ここら辺は好みかもです。
終わりに
以上で終わりです!
思い当たる限り書いたのですがあとで思い出して書き足すかもしれません・・・!!
こうしてみると僕が保守的なのもあるんですが、スター数多いやつばっかですね。スター数以前は300いったら良い方ぐらいだったような気がしています。
これも流行ってきた証ですね!
これ忘れるとは何事だ?などございましたらお教え頂けますと幸いです!
ではみなさま、素敵なイブをお過ごしくださいませーー!!