0
votes

I have connected my component to redux, defined mapStateToProps and mapDispatchToProps and still dispatch doesn't seem to be doing anything.

When I run this, 'console.log("Setting token")' is printed out, but nothing else happens. So this.props.setToken is firing, because that's where that console.log is set, but the store isn't updating and this.props.auth_token isn't showing on the screen like it should if dispatch(setToken) had fired correctly...

AppScreen

import React from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import { connect } from 'react-redux';
import { setToken } from './reducer';

class AppScreen extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    this.props.setToken("token_abc");
  }

  render() {
    if (this.props.loading) {
      return (
        <View style={{ flex: 1 }}>
          <ActivityIndicator />
        </View>
      )
    } else {
      return (
        <View>
          <Text>You're in! '{this.props.auth_token}'</Text>
        </View>
      )
    }
  }
}

function mapStateToProps(state) {
  return {
    user: state.user,
    auth_token: state.auth_token,
    loading: state.loading,
    error: state.error
  };
}

const mapDispatchToProps = dispatch => {
  return {
    setToken: token => {
      console.log("Setting token")
      dispatch(setToken(token));
    }
  }
}

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

Reducer

import { createSlice } from "@reduxjs/toolkit";
const appSlice = createSlice({
  name: "app",
  initialState: {
    loading: true,
    auth_token: "",
    error: "",
    user: {}
  },
  reducers: {
    setToken: (state, action) => {
      state.auth_token = action.payload;
      state.loading = false;
    },
  },
  extraReducers: {
  }
});

export const { setToken } = appSlice.actions;
export const appReducer = appSlice.reducer;

Store

import { appReducer } from "./App/reducer";
import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";

const middleware = [
  ...getDefaultMiddleware(),
]

const store = configureStore({
  reducer: {
    app: appReducer
  },
  middleware,
});

export default store;
1

1 Answers

1
votes

You've got a mismatch between the combined store reducer setup, and what your mapState is trying to do.

Your component expects that state.auth_token will exist. The appSlice.reducer has an auth_token field inside. Therefore, state.auth_token will only exist if appSlice.reducer is the root reducer for the entire store.

However, you're currently passing appSlice.reducer as a "slice reducer" for state.app, which will result in state.app.auth_token.

You need to either pass reducer: appReducer to make it be the root reducer by itself, or update your mapState to read state.app.auth_token.

Given that you're likely going to have other slices, I'd recommend the latter approach.