LoginSignup
0
1

More than 5 years have passed since last update.

React NavigatorでTabにStack入れ子にしてReduxでstate管理

Last updated at Posted at 2018-10-25

あまりサンプルが無いので自分用にメモ。
根本を理解していないのでズレてるかも(でも期待の動作はします)。

動作イメージ

下記のような感じ。Settingsで値いじったら、その他の画面にも反映・利用できるようにしたい。
ユーザープロファイルを引き回すイメージなので、name変数とそれを変更するupdateName()を引き回す。

スクリーンショット 2018-10-25 15.32.50.png

ディレクトリ構造

とりあえずRedux-way風。いまいち落ち着かない。

Web Image 2018-10-25 15-35-43.png

以下、実装を見ていきます。

環境

expを利用しますが、create-react-native-appでも基本同じかと。

exp init demo
cd demo
npm install --save redux react-redux react-navigation
npm install

実装

App.js

まずはApp.js。基本的な流れをわかりやすく?するために、tab, stack, storeの紐づけを書いている。

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Provider } from 'react-redux';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import createStore from './createStore';

//screens
import HomeScreen from './screens/HomeScreen';
import AboutScreen from './screens/AboutScreen';
import SettingsScreen from './screens/SettingsScreen';

//store
const store = createStore();

//stack
const Stack = createStackNavigator(
  {
      Home: HomeScreen,
      About: AboutScreen,
  },
  {
      initialRouteName: 'Home',
  }
);

//tabs
const Tabs = createBottomTabNavigator(
  {
    Top: Stack,
    Settings: SettingsScreen
  }
);

//main
export default class App extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <Tabs/>
      </Provider>
    );
  }
}

createStore.js

今回はuser情報のみを扱うので本当はuserReducerだけあればいい。stackやnavの初期値を引き回すサンプルもあるけど、今ひとつ意味がわからないので放って置く。設定せずとも独自の値は引き回せる。

import { createStore as reduxCreateStore, combineReducers, compose, applyMiddleware } from "redux";
import { stackReducer } from "./reducers/stackReducer";
import { tabReducer } from "./reducers/tabReducer";
import userReducer from "./reducers/userReducer";

export default function createStore(){
    const store = reduxCreateStore(
        combineReducers({
            stack: stackReducer,
            tab: tabReducer,
            user: userReducer
        }),
    );
    return store;
}

HomeScreen.js

ただ表示しているだけ。

import React from 'react';
import { Button, View, Text } from 'react-native';
import { connect } from 'react-redux';
import { updateName } from '../actions/userAction';

class HomeScreen extends React.Component {
    render() {
        // console.log(this.props);
        return (
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
                <Text>Home</Text>
                <Button
                    title='Link to About'
                    onPress={() => this.props.navigation.navigate('About')}
                />
                <Text>{this.props.user.name}</Text>
            </View>
        );
    }
}

const mapStateToProps = state => ({
    user: state.user
});

const mapDispatchToProps = dispatch => {
    return {
        updateName: (name) => dispatch(updateName(name))
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(HomeScreen);

// export default HomeScreen;

AboutScreen.js

ただ表示してるだけ。いちおうボタンつけて値(名前)をAboutでも更新できるようにしてみた。

import React from 'react';
import { Button, View, Text } from 'react-native';
import { connect } from 'react-redux';
import { updateName } from '../actions/userAction';

class AboutScreen extends React.Component {
    render() {
        // console.log(this.props);
        return (
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
                <Text>About</Text>
                <Text>{this.props.user.name}</Text>
                <Button
                    title='名前の変更'
                    onPress={()=>this.props.updateName('yamada@about')}
                />
            </View>
        );
    }
}

const mapStateToProps = state => ({
    user: state.user
});

const mapDispatchToProps = dispatch => {
    return {
        updateName: (name) => dispatch(updateName(name))
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(AboutScreen);

// export default AboutScreen;

SettingsScreen.js

値の表示と変更用のボタン。

import React from 'react';
import { Button, View, Text } from 'react-native';
import { connect } from 'react-redux';
import { updateName } from '../actions/userAction';

class SettingsScreen extends React.Component {
    render() {
        // console.log(this.props);
        return (
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
                <Text>Settings</Text>
                <Text>{this.props.user.name}</Text>
                <Button
                    title='名前の変更'
                    onPress={()=>this.props.updateName('suzuki@settings')}
                />
            </View>
        );
    }
}

const mapStateToProps = state => ({
    user: state.user
});

const mapDispatchToProps = dispatch => {
    return {
        updateName: (name) => dispatch(updateName(name))
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(SettingsScreen);

// export default SettingsScreen;

userReducer.js

初期値の設定と、変更するための機能を実装。

// export const userReducer = (state = {}) => state;

const initialState = {
    name: 'tanaka',
    age: 44
}

const userReducer = (state = initialState, action) => {
    // console.log(action);
    switch(action.type){
        case 'UPDATE_NAME':
            const updateState = Object.assign({}, state);
            updateState.name = action.name
            return updateState;
        default:
            return state;
    }
}

export default userReducer;

stackReducer.js

まんま返してるだけ。必要に応じて実装。

export const stackReducer = (state = {}) => state;

tabReducer.js

まんま返してるだけ。必要に応じて実装。

export const stackReducer = (state = {}) => state;

userAction.js

名前更新用のActionを実装。

export const updateName = name => {
    return {
        type: 'UPDATE_NAME',
        name: name
    }
}

まあ、とりあえず動いてます。

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