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@gmail.com" : "",
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,
},
});
In your AuthAction.js
, you have a call to dispatch()
without arguments. You have to dispatch something, or you'll provoke this error.
If you don't want to dispatch anything there, remove that line.
const userData = await createUser(username, email, uid);
dispatch(authenticate({ token: accessToken, userData }));
saveToDataStorage(accessToken, uid, expiryDate);
// remove this line
// dispatch();
} catch (error) {