0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Expo+Redux(+firebase)でログインフォーム② 〜Reduxの導入〜

Last updated at Posted at 2020-02-20

はじめに

Expo+Redux(+firebase)でログインフォーム① 〜概要・Expoの準備〜の続きです。

今回の記事では、Reduxを使って、まずは簡単なカウンターを作っていきます。
次々回の記事で、ログイン画面と画面遷移を実装していく予定です。

現在のディレクトリ構成

root/
 ├ App.js
 ├ package.json

srcディレクトリの作成

rootに色々と詰め込んでいくとわかりにくくなるので、srcディレクトリを作ってAppを移しましょう
Expoはデフォルトでroot/App.jsを読み込むようになっているので、これを変更するために、node_modules/expo/AppEntry.jsを編集します

/node_modules/expo/AppEntry.js
-- import App from '../../App';
++ import App from '../../src/App';

そしてroot/App.jsを削除し、root/src/App.tsxを書いていきます。

Reduxを導入

まずはApp.tsxにreduxを入れていきます
とりあえず最小の構成で、1ファイルにまとめています

src/App.tsx
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { createStore, combineReducers } from 'redux'
import { Provider, connect } from 'react-redux'

// reducer
function counter(state, action) {
  if (action.type === 'undefined') {
    return null
  }

  switch(action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return null
  }
}

// store
const store = createStore(combineReducers({ count: counter }))

// component
function Counter({ count, dispatch }) {
  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>{count}</Text>
      <Button
        title='Increment'
        onPress={() => dispatch({ type: 'INCREMENT' })}
      />
      <Button
        title='DECREMENT'
        onPress={() => dispatch({ type: 'DECREMENT' })}
      />
    </View>
  )
}

// container
const CounterContainer = connect(state => ({ count: state.count }))(Counter)

export default function App() {
  return (
    <Provider store={store}>
      <CounterContainer />
    </Provider>
  )
}

// スタイル
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#ecf0f1',
    padding: 8,
  },
  paragraph: {
    margin: 24,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
  },
})

Reducer

App.tsx
// reducer
function counter(state, action) {
  if (action.type === 'undefined') {
    return null
  }

  switch(action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return null
  }
}

actionと現在のstateを受け取って、新しいstateを返す関数です。
actionがない時や、swich文のdefaultでnullを返すようにしないとエラーになるので、注意が必要です。

Store

root/App.tsx
// store
const store = createStore(combineReducers({ count: counter }))

Reducerが今後増えることを踏まえて、combineReducerでまとめておきます。

Component/Container

App.tsx
// component
function Counter({ count, dispatch }) {
  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>{count}</Text>
      <Button
        title='Increment'
        onPress={() => dispatch({ type: 'INCREMENT' })}
      />
      <Button
        title='DECREMENT'
        onPress={() => dispatch({ type: 'DECREMENT' })}
      />
    </View>
  )
}

// container
const CounterContainer = connect(state => ({ count: state.count }))(Counter)

画面に表示する部分です。
ボタンを押すと、typeがINCREMENT/DECREMENTのactionがdispatchされます。
ボタンを押した時のコールバック関数は、本来はContainer側に書くべきだとは思いますが、コードが少しややこしくなるので、それは後にしようと思います。

App

App.tsx
export default function App() {
  return (
    <Provider store={store}>
      <CounterContainer />
    </Provider>
  )
}

ReactNativeは、で囲ってstoreを渡してやれば、Reduxと接続することができます。

ここまでで実行するとこんな感じ
gif.gif

次回

今回は最低構成のreduxを組んでみたので、次回はDucksパターンを意識してファイルを分けていきたいと思います。
その後、ReactNativeDebuggerも使えるようにしていきます。
Expo+Redux(+firebase)でログインフォーム③ 〜ファイル整理・Debugger〜

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?