Help us understand the problem. What is going on with this article?

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

はじめに

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〜

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした