Currently, I'm trying to create a login and for some reason my code for my login is not being triggered. The function loginUserWithEmail is not being triggered.
It is not being triggered because none of the console.log's inside the loginUserWithEmail function is printed in the console.
The onSubmit() function in Login.tsx is triggers when I click a "Login" button.
Thank you.
Login.tsx:
import { useFormik } from 'formik';
import { loginUserWithEmail, LoginFormData } from '../../actions/authActions'
const Login = ({ auth, history, login }: {auth: any, history: RouteComponentProps['history'], login: any}) => {
const formik = useFormik({
initialValues: {
email: '',
password: '',
},
validationSchema: loginSchema,
onSubmit: (values: LoginFormData) => {
console.log("before loginuserwithemail");
loginUserWithEmail(values, history);
console.log("after")
},
});
...
}
authActions.ts
export const loginUserWithEmail = (formData: LoginFormData, history: RouteComponentProps['history']) => async (dispatch: any, getState: any) => {
console.log("inside loginuserwithemail function")
dispatch({ type: LOGIN_WITH_EMAIL_LOADING });
try {
const response = await axios.post('/auth/login', formData);
console.log("inside here")
dispatch({
type: LOGIN_WITH_EMAIL_SUCCESS,
payload: { token: response.data.token, me: response.data.me },
});
dispatch(loadMe());
history.push('/');
} catch (err: any) {
dispatch({
type: LOGIN_WITH_EMAIL_FAIL,
payload: { error: err.response.data.message },
});
}
};
loginUserWithEmail is hoc (function that returns function)
You need it to call function returned by this function
await loginUserWithEmail(values, history)(dispatch, getState);
Related
So basically as the APP.js renders it is not sending requests to the backend. I am calling the currentUser function inside App.js function. Please help me I am stuck
app.js file
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(async (user) => {
if (user) {
const getidtoken = await user.getIdTokenResult();
currentUser(getidtoken.token)`enter code here`
.then((res) => {
console.log(res);
dispatch({
type: 'LOGGED_IN_USER',
payload: {
email: res.data.email,
name: res.data.name,
role: res.data.role,
_id: res.data._id,
},
});
})
.catch((err) => {
console.log(err);
});
}
});
currentuser.js Function
export const currentUser = async (authtoken) => {
return await axios.post(
process.env.REACT_APP_API_USER,
{},
{ headers: { authtoken: authtoken } }
);
};
enter image description here
I have a simple auth stack as follow
export default () => {
const { state } = useContext(AuthContext);
return (
<AuthProvider>
<NavigationContainer>
{state.token ? <MainNavigator /> : <AuthNavigator />}
</NavigationContainer>
</AuthProvider>
);
};
The initial state of token is defined as null in the AuthContext folder, code below. But when running the program i get the following error TypeError: undefined is not an object (evaluating '_useContext.state')
const authReducer = (state, action) => {
switch (action.type) {
case "error":
return { ...state, errorMessage: action.payload };
case "signin":
return { errorMessage: "", token: action.payload };
default:
return state;
}
};
const tokencheck = (dispatch) => async () => {
const token = await AsyncStorage.getItem("token");
if (token) {
dispatch({ type: signin, payload: token });
navigate("Home");
} else {
navigate("SignIn");
}
};
const signup =
(dispatch) =>
async ({ username, password }) => {
try {
const response = await tracker({
method: "post",
url: "/user",
data: qs.stringify({
username: username,
password: password,
}),
headers: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
});
await AsyncStorage.setItem("token", response.data.email);
// dispatch({ type: "signin", payload: response.data.access_token });
navigate("SignIn");
} catch (err) {
dispatch({
type: "error",
payload: "Something's not write, plz try again",
});
console.log(err);
}
};
const signin =
(dispatch) =>
async ({ username, password }) => {
try {
const response = await tracker({
method: "post",
url: "/login",
data: qs.stringify({
username: username,
password: password,
}),
headers: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
});
await AsyncStorage.setItem("token", response.data.access_token);
dispatch({ type: "signin", payload: response.data.access_token });
navigate("Home");
} catch (err) {
console.log(err);
dispatch({
type: "error",
payload: "Start debuggin",
});
}
};
const signout = (dispatch) => {
return () => {};
};
export const { Provider, Context } = creatingContext(
authReducer,
{ signin, signout, signup, tokencheck },
{ token: null, errorMessage: "" }
);
The ternary logic is sound and I have defined the initial state then why is this error persisting.
While I was looking for state in token what i should look for is value.
The problem is simply solved with
{state.token != null : <nav/>?<auth/>}
I am making a blog app. Where if I try to access the individual profiles the spinner keeps running, but the data is there when I check in the react dev tools. Where did I go wrong? Everything else was working fine. The profiles are visible, but when I get inside the individual profile is where the problem happens
Profile.js
import React, { Fragment, useEffect } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import Spinner from "../layout/Spinner";
import { getProfileById } from "../../actions/profile";
import { Link } from "react-router-dom";
const Profile = ({ getProfileById, profile: { profile }, auth, match }) => {
useEffect(() => {
getProfileById(match.params.id);
}, [getProfileById, match.params.id]);
return (
<Fragment>
{profile === null ? (
<Spinner />
) : (
<Fragment>
<Link to='/profiles' className='btn btn-light'>
Back to Profiles
</Link>
{auth.isAuthenticated &&
auth.loading === false &&
auth.user._id === profile.user._id && (
<Link to='/edit-profile' className='btn btn-dark'>
Edit Profile
</Link>
)}
</Fragment>
)}
</Fragment>
);
};
Profile.propTypes = {
getProfileById: PropTypes.func.isRequired,
profile: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
profile: state.profile,
auth: state.auth,
});
export default connect(mapStateToProps, { getProfileById })(Profile);
The source from which the data is comming, profile.js
import axios from "axios";
import { setAlert } from "./alert";
import {
GET_PROFILE,
PROFILE_ERROR,
UPDATE_PROFILE,
ACCOUNT_DELETED,
CLEAR_PROFILE,
GET_PROFILES,
GET_REPOS,
} from "./types";
export const getCurrentProfile = () => async (dispatch) => {
try {
const res = await axios.get("/api/profile/me");
dispatch({
type: GET_PROFILE,
payload: res.data,
});
} catch (error) {
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
//Get all profiles
export const getProfiles = () => async (dispatch) => {
dispatch({ type: CLEAR_PROFILE });
try {
const res = await axios.get("/api/profile");
dispatch({
type: GET_PROFILES,
payload: res.data,
});
} catch (error) {
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
//Get Profile by id
export const getProfileById = (userId) => async (dispatch) => {
try {
const res = await axios.get(`/api/profile/user/${userId}`);
dispatch({
type: GET_PROFILES,
payload: res.data,
});
} catch (error) {
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
//Get github repos
export const getGithubRepos = (username) => async (dispatch) => {
try {
const res = await axios.get(`/api/profile/github/${username}`);
dispatch({
type: GET_REPOS,
payload: res.data,
});
} catch (error) {
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
//Create or Update profile
export const createProfile =
(formData, history, edit = false) =>
async (dispatch) => {
try {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const res = await axios.post("/api/profile", formData, config);
dispatch({
type: GET_PROFILE,
payload: res.data,
});
dispatch(setAlert(edit ? "Profile Updated" : "Profile Created"));
if (!edit) {
history.push("/dashboard");
}
} catch (error) {
const errors = error.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, "danger")));
}
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
//Add experience
export const addExperience = (formData, history) => async (dispatch) => {
try {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const res = await axios.put("/api/profile/experience", formData, config);
dispatch({
type: UPDATE_PROFILE,
payload: res.data,
});
dispatch(setAlert("Experience Added", "success"));
history.push("/dashboard");
} catch (error) {
const errors = error.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, "danger")));
}
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
//Add Education
export const addEducation = (formData, history) => async (dispatch) => {
try {
const res = await axios.put("/api/profile/education", formData);
dispatch({
type: UPDATE_PROFILE,
payload: res.data,
});
dispatch(setAlert("Education Added", "success"));
history.push("/dashboard");
} catch (error) {
const errors = error.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, "danger")));
}
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
// Delete experience
export const deleteExperience = (id) => async (dispatch) => {
try {
const res = await axios.delete(`/api/profile/experience/${id}`);
dispatch({
type: UPDATE_PROFILE,
payload: res.data,
});
dispatch(setAlert("Experience Deleted", "success"));
} catch (error) {
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
// Delete education
export const deleteEducation = (id) => async (dispatch) => {
try {
const res = await axios.delete(`/api/profile/education/${id}`);
dispatch({
type: UPDATE_PROFILE,
payload: res.data,
});
dispatch(setAlert("Education Deleted", "success"));
} catch (error) {
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
//Delete account & profile
export const deleteAccount = () => async (dispatch) => {
if (
window.confirm("Are you sure? This will be permanently delete the account!")
)
try {
await axios.delete(`/api/profile`);
dispatch({
type: CLEAR_PROFILE,
});
dispatch({
type: ACCOUNT_DELETED,
});
dispatch(setAlert("Account Removed"));
} catch (error) {
dispatch({
type: PROFILE_ERROR,
payload: {
msg: error.response.statusText,
status: error.response.status,
},
});
}
};
My github repo Link
Your actions expect a dispatch function as the second function's parameter. But you aren't providing it anywhere.
Considering how your actions are written this should resolve the issue:
const dispatch = useDispatch();
useEffect(() => {
getProfileById(match.params.id)(dispatch);
}, [dispatch, getProfileById, match.params.id]);
Also, you are providing getProfileById as the component property and you have it as an import on top of the file.
It worked.
There was some error in the getProfilebyID function.
under src -> components -> profile.js
at the bottom you did define mapStateToProps, however you never created the function mapDispatch which is used to grab the data from your thunk call getProfileById
here is more info:
ctrl + find -> mapDispatchToProps
https://react-redux.js.org/api/connect
How can I use the current status of redux after the thunks and actions have finished? The problem is in the handleSubmit function if I register a user with errors, it updates the status of redux with the message "Email already registered", but when accessing the state in the dispatch promise sends me a wrong state, without the message.
Function hanldeSubmit
const handleSubmit = (e) => {
e.preventDefault()
const form = {
name: e.target[0].value,
email: e.target[1].value,
password: e.target[2].value,
confirmPassword: e.target[3].value
}
const { name, email, password } = form
if (isFormValid(form)) {
//TODO: FIX IT synchronize redux with errors
dispatch( startRegisterUser(name, email, password) ).then(() => {
console.log(state)
})
}
}
register action and thunk
export const startRegisterUser = (name, email, password) => {
return (dispatch, state) => {
dispatch(startLoadingAction())
return firebase.auth().createUserWithEmailAndPassword(email, password)
.then(async ({ user }) => {
await user.updateProfile({
displayName: name,
photoURL: ''
})
dispatch(registerUserAction(user.uid, user.displayName))
})
.catch(e => {
if (e.code === "auth/email-already-in-use") {
dispatch(errorAction("Email already registered"))
} else {
dispatch(errorAction("Unexpected error"))
}
})
.then(() => {
dispatch(finishLoadingAction())
console.log("finished dispatch's", state())
return
})
}
}
export const registerUserAction = (uid, displayname) => {
return {
type: types.register,
payload: {
uid,
displayname
}
}
}
console logs
I want to get the status of the first console log but in the handlesubmit function
You should handle the errorAction in the reducer, update the ui store slice with the error message. And, you need to return the state() in the promise in the thunk function. Then, you will get the whole state inside the handleSubmit event handler.
E.g.
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
function errorAction(message) {
return {
type: 'ERROR',
payload: message,
error: true,
};
}
export const startRegisterUser = (name, email, password) => {
return (dispatch, state) => {
return Promise.reject({ code: 'auth/email-already-in-use' })
.catch((e) => {
if (e.code === 'auth/email-already-in-use') {
dispatch(errorAction('Email already registered'));
} else {
dispatch(errorAction('Unexpected error'));
}
})
.then(() => state());
};
};
export const registerUserAction = (uid, displayname) => {
return {
type: 'REGISTER',
payload: {
uid,
displayname,
},
};
};
function rootReducer(state = { ui: { error: '' } }, action) {
switch (action.type) {
case 'ERROR':
return { ui: { error: action.payload } };
default:
return state;
}
}
const store = createStore(rootReducer, applyMiddleware(thunk));
function handleSubmit() {
store
.dispatch(startRegisterUser('name', 'example#gmail.com', '123') as any)
.then((state) => {
console.log('handleSubmit state: ', state);
});
}
// triggered by user submit event
handleSubmit();
Output:
handleSubmit state: { ui: { error: 'Email already registered' } }
I'm trying to call a function from React JSX button and I have a problem with that because when in react-redux actions in the defined function I don't put dispatch function, works as it supposed to.
const like_function = (id) => {
let post_id = id;
if (isAuthenticated) {
console.log(post_id, user_id);
like_post(post_id, user_id);
} else {
<Redirect to="/login" />;
console.log("Redirect to login");
}
};
Here in this button I invoke function with one parameter.
<button onClick={() => like_function(post.id)}>Like</button>
This is redux action. Here is the problem. When dispatch is deleted function works but with dispatch is not even called, it wont even log data to console before async request
export const like_post = (post_id, user_id) => async (dispatch) => {
const data = { post_id: post_id, user_id: user_id };
console.log(data);
dispatch({
type: POST_LIKE_LOADING,
});
try {
const res = await axios.put(`http://localhost:8000/api/like_list/`, data);
//console.log(res.data);
dispatch({
type: POST_LIKED,
payload: res.data,
});
} catch (err) {
console.log(err);
dispatch({
type: POST_LIKEING_FAIL,
});
}
};
Here are my redux reducers
case POST_LIKE_LOADING:
return {
...state,
isLoading: true,
};
case POST_LIKED:
return {
...state,
isLoading: true,
message: "OK"
};
Sorry about my English, hope you understood me, thanks in advance
You're not dispatching the action.
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
dispatch(like_post(post_id, user_id))