質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • React.js

    1038questions

    Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

  • React Native

    239questions

    React Nativeは、ネイティブモバイルアプリ(iOS/Android)を作成できるJavaScriptフレームワークです。Reactと同じ設計のため、宣言的なコンポーネントでリッチなUIを開発することが可能です。

  • Redux

    140questions

Expected the reducer to be a functionエラーでreducerが通らない(react-redux)

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 832

yamady

score 161

React Nativeでスマートフォン専用のアプリを開発しています。
App.jsにてcreateStoreを設定しようとしているのですが、下記のエラーが出てしまい通らずに困っています。

アプリの内容は雇用者を管理して、情報を投稿するアプリを想定しています。

Expected the reducer to be a function

`

 ソースコード

App.js

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { createStore, applyMiddleware } from 'redux';
import firebase from 'react-native-firebase';
import { GoogleSignin } from 'react-native-google-signin';
import { Provider } from 'react-redux';
import ReduxThunk from 'redux-thunk';

import { GOOGLE_SIGN_IN_ANDROID_CLIENT_ID, GOOGLE_SIGN_IN_IOS_CLIENT_ID } from './config';
import { store, rootReducer } from './redux/store';

import LoadingModal from './ui/components/LoadingModal';
import LoggedIn from './loggedin/screens';
import LoggedOut from './loggedout/screens';

GoogleSignin.configure({
  iosClientId: GOOGLE_SIGN_IN_IOS_CLIENT_ID,
  webClientId: GOOGLE_SIGN_IN_ANDROID_CLIENT_ID,
});

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
});

type State = {
  loading: boolean,
  user?: Object,
}

export default class App extends React.Component<*, State> {
  authSubscription: () => any;
  state: State;

  constructor() {
    super();
    this.state = {
      loading: true,
    };
  }

   componentDidMount() {
     this.authSubscription = firebase.auth().onAuthStateChanged((user) => {
       this.setState({
         loading: false,
         user,
       });

       firebase.analytics().setUserId(user ? user.uid : null);
     });
   }

   componentWillUnmount() {
     this.authSubscription();
   }

  render() {
    const store = createStore(rootReducer, {}, applyMiddleware(ReduxThunk));
    if (this.state.loading) return null;

    return (
      <Provider store={store}>
        <View style={styles.container}>
          <LoadingModal />
          {this.state.user ? <LoggedIn /> : <LoggedOut />}
        </View>
      </Provider>
    );
  }
}

redux/store.js

import { createStore, combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';

import uiReducer from '../ui/redux/uiReducer';
import employeeFormReducer from '../ui/redux/employeeFormReducer';
import employeeReducer from '../ui/redux/employeeReducer';

const rootReducer = combineReducers({
  form: formReducer,
  ui: uiReducer,
  employeeForm: employeeFormReducer,
  employees: employeeReducer
});

const store = createStore(rootReducer);
export default store;

 試してみたこと

rootReducerの部分をstoreに変えてみたりもしました。

 追記

reduxを読み込んでいるスクリプトを追記します。

uiReducer.js

type UiAction = {
  type: 'ui/loading/hide' | 'ui/loading/show',
}

type UiReduxState = {
  loading: boolean,
}

const initialState = {
  loading: false,
};

export default (state: UiReduxState = initialState, action: UiAction): UiReduxState => {
  switch (action.type) {
    case 'ui/loading/hide':
      return {
        ...state,
        loading: false,
      };

    case 'ui/loading/show':
      return {
        ...state,
        loading: true,
      };

    default:
      return state;
  }
};

const isLoading = (state: { ui: UiReduxState }) => state.ui.loading;

export const Store = ({
  isLoading,
});

employeeForm.js

type UiAction = {
  type: 'employee_update',
  type: 'employee_create'
}

const initialState = {
  title: '',
  category: '',
  address: '',
  price: ''
};

export default  (state = initialState, action) => {
  switch (action.type) {
    case 'employee_update':
      return {...state, [action.payload.prop]: action.payload.value };
    case 'employee_create':
      return initialState;
    default:
      return state;
  }
};

employeeReducer.js

type UiAction = {
  type: 'employees_fetch_success',
}

const initialState = {};

export default  (state = initialState, action) => {
  switch (action.type) {
    case 'employees_fetch_success':
      return action.payload;
    default:
      return state;
  }
};

 追記②

ご指摘いただいたようにすると、どうやらredux部分は解決したように思えるのですが(ありがとうございます!)根本的なエラーはこちらであったようなきがします。

Actions must be plain objects. Use custom middleware for async actions.

もしかしたら、自分の書き方がひどすぎるのかもしれません(涙

エラーの続き

This error is located at:
    in Home (created by Connect(Home))
    in Connect(Home) (at SceneView.js:31)
    in SceneView (at CardStack.js:405)
    in RCTView (at View.js:71)
    in View (at createAnimatedComponent.js:147)
    in AnimatedComponent (at Card.js:26)
    in Card (at PointerEventsContainer.js:55)
    in Container (at CardStack.js:436)
    in RCTView (at View.js:71)
・・・

 ソースコード

Home.js

import _ from 'lodash';
import React from 'react';
import { connect } from 'react-redux';
import { ListView, Image, Text, View, StyleSheet } from 'react-native';
import Screen from '../../ui/components/Screen';
import { employeesFetch } from '../../ui/redux/uiActions';

const styles = StyleSheet.create({

});

class Home extends React.Component {
  // Set the navigation options for `react-navigation`
  static navigationOptions = {
    headerTitle: 'Home',
  };

  componentWillMount() {
    this.props.employeesFetch();

    this.createDataSource(this.props);
  }

  componentWillReceiveProps(nextProps) {

    this.createDataSource(nextProps);
  }

  createDataSource({ employees }) {
    const ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1 !==r2
    });

    this.dataSource = ds.cloneWithRows(employees);
  }

  render() {
    console.log(this.props);

    return (
      <Screen>
        <View>
          <Text>Employee List</Text>
          <Text>Employee List</Text>
          <Text>Employee List</Text>
          <Text>Employee List</Text>
        </View>
      </Screen>
    );
  }
}

const mapStateToProps = state => {
  const employees = _.map(state.employees, (val, uid) => {
    return { ...val, uid };
  });

  return { employees };
}

export default connect(mapStateToProps, { employeesFetch })(Home);
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • januswel

    2018/02/11 00:15

    uiReducer の定義を教えてください

    キャンセル

回答 2

checkベストアンサー

+1

App.js の render の中の次の行を削除してみてください。

    const store = createStore(rootReducer, {}, applyMiddleware(ReduxThunk));

store は redux/store.js で作成しているものをそのまま使うとよいです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/11 21:53

    本当にありがとうございます!なるほど、storeをそのまま使えば良かったんですね。やってみた結果、別のエラーが生じてしまい。。泣
    Actions must be plain objects. Use custom middleware for async actions.
    なのですが、これは別ソースの方でconnectしてるからapp.jsで定義しろということなのでしょうが・・・汗

    キャンセル

  • 2018/02/11 21:58

    Action がプレインオブジェクトじゃないということで怒られているので、 Action Creator が `return` しているものを確認してみてください。
    `type` プロパティを持ったプレインオブジェクトになっていればこのエラーは解決するはずです

    キャンセル

  • 2018/02/14 17:39

    ありがとうございます!

    キャンセル

+1

uiReducer の定義はどうなっていますか ?
多分この定義が関数となっていない可能性があります。

import uiReducer from '../ui/redux/uiReducer';

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/11 09:36

    いつもありがとうございます。こちらuiReducerおよび読み込んでいるreducerを追記させていただきました。(_ _)
    ここまでは普通に動いていたのですが。。。

    キャンセル

同じタグがついた質問を見る

  • React.js

    1038questions

    Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

  • React Native

    239questions

    React Nativeは、ネイティブモバイルアプリ(iOS/Android)を作成できるJavaScriptフレームワークです。Reactと同じ設計のため、宣言的なコンポーネントでリッチなUIを開発することが可能です。

  • Redux

    140questions