Redux: Actions must be plain objects error - How to resolve?

47 Views Asked by At

I'm encountering an error in my React Native application when trying to save user data and login details to Firebase using Redux. The error message I'm receiving is:

[Error: Actions must be plain objects. Instead, the actual type was: 'undefined'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions.

I'm using Redux to manage my application's state, and I've configured a store using @reduxjs/toolkit. The strange thing is that the data is being saved successfully to Firebase, but I'm still getting this error.

Here's a simplified version of my Redux setup:

Signup.js

const isTestMode = true;
const initialState = {
  inputValues: {
    username: isTestMode ? "John Doe" : "",
    email: isTestMode ? "[email protected]" : "",
    password: isTestMode ? "12121212" : "",
  },
  inputValidities: {
    username: false,
    email: false,
    password: false,
  },
  formIsValid: false,
};

export default function Signup({ navigation }) {
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
  const [formState, dispatchFormState] = useReducer(reducer, initialState);
  const dispatch = useDispatch();

  const inputChangedHandler = useCallback(
    (inputId, inputValue) => {
      const result = validateInput(inputId, inputValue);
      dispatchFormState({ inputId, validationResult: result, inputValue });
    },
    [dispatchFormState]
  );

  const signupHandler = async () => {
    try {
      setIsLoading(true);
      const action = signUp(
        formState.inputValues.username,
        formState.inputValues.email,
        formState.inputValues.password
      );
      await dispatch(action);
      Alert.alert("Account Successfully created", "Account created");
      setError(null);
      setIsLoading(false);
      navigation.navigate("Login");
    } catch (error) {
      console.log(error);
      setIsLoading(false);
      setError(error.message);
    }
  };

 
  return (
    <SafeAreaProvider>
      <View style={styles.container}>
        <View style={styles.inputView}>
          <Inputs
            id="username"
            placeholder="Username"
            errorText={formState.inputValidities["username"]}
            onInputChanged={inputChangedHandler}
          />
          <Inputs
            id="email"
            placeholder="Enter your email"
            errorText={formState.inputValidities["email"]}
            onInputChanged={inputChangedHandler}
          />
          <InputsPassword
            id="password"
            placeholder="Password"
            errorText={formState.inputValidities["password"]}
            onInputChanged={inputChangedHandler}
          />
        </View>

        <Buttons
          title="SIGN UP"
          onPress={signupHandler}
          isLoading={isLoading}
        />

        <StatusBar style="auto" />
      </View>
    </SafeAreaProvider>
  );
}

AuthSlice.js

import { createSlice } from "@reduxjs/toolkit";

const authSlice = createSlice({
  name: "auth",
  initialState: {
    token: null,
    userData: null,
    didTryAutoLogin: false,
  },
  reducers: {
    authenticate: (state, action) => {
      const { payload } = action;
      state.token = payload.token;
      state.userData = payload.userData;
      state.didTryAutoLogin = true;
    },
    setDidTryAutoLogin: (state, action) => {
      state.didTryAutoLogin = true;
    },
  },
});

export const authenticate = authSlice.actions.authenticate;
export default authSlice.reducer;

AuthAction.js

export const signUp = (username, email, password) => {
  return async (dispatch) => {
    const app = getFirebaseApp();
    const auth = getAuth(app);
    try {
      const result = await createUserWithEmailAndPassword(
        auth,
        email,
        password
      );
      const { uid, stsTokenManager } = result.user;
      const { accessToken, expirationTime } = stsTokenManager;
      const expiryDate = new Date(expirationTime);
      const userData = await createUser(username, email, uid);
      dispatch(authenticate({ token: accessToken, userData }));
      saveToDataStorage(accessToken, uid, expiryDate);
      dispatch();
    } catch (error) {
      console.log(error);
      const errorCode = error.code;
      let msg = "Something went wrong";
      if (
        errorCode === "auth/wrong-password" ||
        errorCode === "auth/user-not-found"
      ) {
        msg = "Invalid email or password";
      }
      throw new Error(msg);
    }
  };
};

const createUser = async (username, email, userId) => {
  const userData = {
    username,
    email,
    userId,
    signUpDate: new Date().toISOString(),
  };
  const dbRef = ref(getDatabase());
  const childRef = child(dbRef, `users/${userId}`);
  await set(childRef, userData);
  return userData;
};

const saveToDataStorage = (token, userId, expiryDate) => {
  AsyncStorage.setItem(
    "userData",
    JSON.stringify({
      token,
      userId,
      expiryDate: expiryDate.toISOString(),
    })
  );
};

Store.js

import { configureStore } from "@reduxjs/toolkit";
import authSlice from "./authSlice";

export const store = configureStore({
  reducer: {
    auth: authSlice,
  },
});
0

There are 0 best solutions below