Can not navigate to another pages after login - javascript

i dont know where is the trouble. but when i tried to login, it dont wanna navigate into the next pages and stuck in modal login. please tell me whats wrong with my code?
let navigate = useNavigate();
const dispatch = useContext(UserContext);
const state = useContext(UserContext);
// console.log(state);
const [form, setForm] = useState({
email: "",
password: "",
});
const { email, password } = form;
const handleChange = (e) => {
setForm({
...form,
[e.target.name]: e.target.value,
});
};
const handleSubmitLog = async (e) => {
try {
e.preventDefault();
const config = {
headers: {
"Content-type": "application/json",
},
};
const body = JSON.stringify(form);
const response = await API.post("/login", body, config);
console.log(response.data);
if (response?.status == 200) {
dispatch({
type: "LOGIN_SUCCESS",
payload: response.data.data,
});
if (response.data.data.status == "admin") {
navigate('/admin')
} else {
navigate('/userid')
}
}
} catch (error) {
console.log(error);
}
}
here is the response in console, i dont know why this dispatch can not work well
{
"status": "Success",
"data": {
"users": {
"name": "mr.x",
"email": "mr.x#mail.com",
"token": "asfsa"
}
}
}
TypeError: dispatch is not a function
at handleSubmitLog (header.js:59:1)
and here is the body from userContext file. please check it and tell me if my code is wrong
export const UserContext = createContext();
const initialState = {
isLogin: false,
user: {},
};
const reducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case "USER_SUCCESS":
case "LOGIN_SUCCESS":
localStorage.setItem("token", payload.token)
return {
isLogin: true,
user: payload,
};
case "AUTH_ERROR":
case "LOGOUT":
localStorage.removeItem("token")
return {
isLogin: false,
user: {},
};
default:
throw new Error();
}
};
export const UserContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<UserContext.Provider value={[state, dispatch]}>
{children}
</UserContext.Provider>
);
};

The UserContext value is an array [state, dispatch]:
<UserContext.Provider value={[state, dispatch]}>
{children}
</UserContext.Provider>
But the component is not correctly accessing the context value:
const dispatch = useContext(UserContext);
const state = useContext(UserContext);
Here both dispatch and state have are the same context value of [state, dispatch].
You need only one useContext(UserContext) access, either of the following:
Save the entire context value and use array indexing:
const userContext = useContext(UserContext);
...
// userContext[0]; state object/value
// userContext[1]; dispatch function
...
userContext[1]({
type: "LOGIN_SUCCESS",
payload: response.data.data,
});
Save the state and dispatch values directly using array destructuring assignment:
const [state, dispatch] = useContext(UserContext);
...
dispatch({
type: "LOGIN_SUCCESS",
payload: response.data.data,
});

Try this:
const { state, dispatch } = useContext(AppContext)

Related

User is returning null even after modifying it with context API

I am making an API call using Axios and after that I am send those details to context API but I am getting null. I am using formik to send data to backend and on submit of that form I make an api call using axios then get the user from backend end pass it on to context API.
UserContext
import { createContext, useReducer } from "react";
import UserReducer from "./UserReducer";
const INITIAL_STATE = {
user: null,
};
export const UserContext = createContext(INITIAL_STATE);
export const UserContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(UserReducer, INITIAL_STATE);
const setUser = (userDetails) => {
dispatch({
type: "GET_USER",
payload: userDetails,
});
// Here it is returning the user data but INITIAL_STATE.user is null
};
return (
<UserContext.Provider
value={{
user: state.user,
setUser,
}}
>
{children}
</UserContext.Provider>
);
};
UserReducer
const UserReducer = (state, action) => {
switch (action.type) {
case "GET_USER":
return {
user: action.payload,
};
default:
return state;
}
};
export default UserReducer;
Login
const { user, setUser } = useContext(UserContext);
const formik = useFormik({
initialValues: {
email: "",
password: "",
},
onSubmit: () => {
const getUser = async () => {
const userData = await Axios.post("http://localhost:3001/login", {
email: formik.values.email,
password: formik.values.password,
});
setUser(userData.data); // Here I am sending the data to context API
};
getUser();
},
validationSchema,
});

How can i test custom fetch hook

I am struggling with an issue with the custom fetch hook.Simply i am trying to test my fetch hook if the data already fetched the hook needs to get data from cache instead of api.
The test case fails and looks like caching mechanism not working, but if i try on the browser with manual prop change caching mechanism works properly.
import { render, waitFor } from "#testing-library/react";
const renderList = (filterParams = testFilterParamsList[0]) =>
render(<List filterParams={filterParams} />);
it("should re-render without fetch", async () => {
const { rerender } = renderList(testFilterParamsList[0]);
rerender(<List filterParams={testFilterParamsList[1]} />);
expect(window.fetch).toHaveBeenCalledTimes(1);
});
// useFetch.js
import {useEffect, useReducer} from "react";
const cache = {};
const FETCH_REQUEST = "FETCH_REQUEST";
const FETCH_SUCCESS = "FETCH_SUCCESS";
const FETCH_ERROR = "FETCH_SUCCESS";
const INITIAL_STATE = {
isPending: false,
error: null,
data: [],
};
const useFetch = ({url, filterOptions}) => {
const [state, dispatch] = useReducer((state, action) => {
switch (action.type) {
case FETCH_REQUEST:return {...INITIAL_STATE, isPending: true};
case FETCH_SUCCESS: return {...INITIAL_STATE, isPending: false, data: action.payload};
case FETCH_ERROR: return {...INITIAL_STATE, isPending: false, error: action.payload};
default: return state;
}
}, INITIAL_STATE);
useEffect(() => {
const fetchData = async () => {
dispatch({type: FETCH_REQUEST});
if (cache[url]) {
const data = cache[url];
dispatch({type: FETCH_SUCCESS, payload: data});
} else {
try {
const response = await window.fetch(url);
let data = await response.json();
cache[url] = data
dispatch({type: FETCH_SUCCESS, payload: data});
} catch (err) {
dispatch({type: FETCH_ERROR, payload: err});
}
}
};
fetchData();
}, [filterOptions, url]);
return state;
};
export default useFetch;
// List.js
import useFetch from "../hooks/useFetch";
export const RocketsList = ({ filterParams }) => {
const { isPending, error, data } = useFetch({
url: "https://api.spacexdata.com/v3/launches/past",
name:filterParams.name,
});
return (
<div>
Doesn't matter
</div>
);
};

getting typeError while using dispatch from react context-api

I have created a context store using react context API and I a function to dispatch action on the state but every time I call the function I am getttype errorpeError: dispatch is not a function```
the implementation is of login for the user in react using context API to store the state
my context provider / auth context provider
const INITIAL_STATE = {
user: JSON.parse(localStorage.getItem("user")) || null,
isFetching: false,
error: false,
};
export const AuthContext = createContext(INITIAL_STATE);
export const AuthContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(AuthReducer, INITIAL_STATE);
useEffect(() => {
localStorage.setItem("user", JSON.stringify(state.user));
}, [state.user]);
return (
<AuthContext.Provider
value={{
user: state.user,
isFetching: state.isFetching,
error: state.error,
dispatch: dispatch,
}}
>
{children}
</AuthContext.Provider>
);
};
and every time I useContext to get the values of user,isFetching,error,dispatch
I am getting undefined for dispatch but the other values are coming correct isFetching is coming false as it should be initially but the value of dispatch is coming undefined.
where I am using the context
const { isFetching, dispatch } = useContext(AuthContext);
const handleClick = (e) => {
e.preventDefault();
console.log({ isFetching, dispatch });
dispatch({ type: "LOGIN_START" });
e.preventDefault();
loginCall(
{ email: email.current.value, password: password.current.value },
dispatch
);
};
login call function
export const loginCall = async (userCredential, dispatch) => {
dispatch({ type: "LOGIN_START" });
try {
const res = await axios.post("/auth/login", userCredential);
dispatch({ type: "LOGIN_SUCCESS", payload: res.data });
} catch (err) {
dispatch({ type: "LOGIN_FAILURE", payload: err });
}
};
You need to import AuthContextProvider in index.js
and add this snipet
<AuthContextProvider>
<App/>
</AuthContextProvider>

React.useState, will not update. How do I perform a instant update of React useState?

So I'm setting up a react useContext to share user's data such as the user's name and the login status etc... I make a request to the server every time a user refreshes the app to verify that if they have a valid token, the user can then be logged in. Great, but one problem I keep on running into with react is knowing how to get an instant update of useState, as this is needing to be updated as soon as the user is verified.
I've read that you have to create a new object so that React knows it's a new object and then it'll trigger a re-render... Just about every combination I can think of I've tried. Can someone please clarify for me how it's done?
Option 1:
setUser(prev => {
return { ...prev, ...newObj }
})
Option 2:
setUser({ ...newObj })
Can someone please give me the proper way to get a instant update to the React useState.
Thanks
import React, { useState } from "react";
import { useReadCookie } from "../hooks/cookies";
import UserContext from "./user-context";
const UserContextProvider = ({ children }) => {
const readCookie = useReadCookie;
const [user, setUser] = useState({
name: null,
userID: null,
token: null,
permissions: null,
loginStatus: false,
checkLoginStatusReady: false,
});
const loginStatus = async () => {
return new Promise(async (resolve, rej) => {
// So we'll reach out to the server and check to see if the
// User is logged in
const token = readCookie("token");
if (token && token.length === 174) {
// send a request to see if this is a valid user
const req = await fetch("/api/checkLoginStatus.php");
const res = await req.json();
// console.log(res);
handleLogUserIn(res);
}
console.log(user, "The state variable");
resolve();
});
};
const handleLogUserIn = (res) => {
if (res.success === true) {
const userObj = {
name: res.name,
userID: res.userID,
token: res.token,
permissions: res.permissions,
loginStatus: true,
checkLoginStatusReady: true,
};
console.log(userObj, "the user variable");
setUser({ ...userObj });
}
else {
console.log("Not going here");
const userObj = {
name: null,
userID: null,
token: null,
permissions: null,
loginStatus: false,
checkLoginStatusReady: true,
};
setUser({ ...userObj });
}
};
return (
<UserContext.Provider
value={{
username: user.username,
userID: user.userID,
token: user.token,
permissions: user.permissions,
loginStatus: user.loginStatus,
checkLoginStatusReady: loginStatus,
setUser,
}}
>
{children}
</UserContext.Provider>
);
};
export default UserContextProvider;
you can use useEffect for listening to the state update
example if using
const [state, setState] = useState({
username : "",
status : "",
})
useEffect(() => {
setState({
...state,
username : state.username,
status : "active,
})
},[state])
or if using context :
On parent provider.js:
import React, { useState } from 'react'
export const UserContext = React.createContext({
username: "",
status: "active",
setUser: () => {}
})
export const UserContextProvider = (props) => {
const setUser = (param) => {
setState({...state, username: param.username, status: param.status})
}
const initState = {
username: "",
status: "active",
setUser: () => {}
}
const [state, setState] = useState(initState)
return (
<UserContext.Provider value={state}>
{props.children}
</UserContext.Provider>
)
}
On Component:
import React, { useContext } from 'react'
import provider from './provider'
function Component() {
const context = useContext(provider.UserContext)
const onClick = () => {
// do hit api
if(token){
state.setUser({username : "a", status:"inactive"})
}
}
return (
<provider.UserContextProvider>
<buttin onClick={onClick}></button>
<div>username : {state.username}</div>
<div>status : {state.status}</div>
</provider.UserContextProvider>
)
}

How to Pass Id correctly to Rest API Endpoint from React

I'm trying to fetch data through endpoint from Django Rest Framework
endpoint is :
/api/v1/categories/nested/{id}/
Problem is when I'm requesting with id, Django server show this error :
ValueError: Field 'id' expected a number but got 'undefined'.
[07/Feb/2022 15:53:01] "GET /api/v1/categories/nested/undefined/ HTTP/1.1" 500 162581
As this suggest I'm unable to Pass id correctly,
So need littl help to fix that
I'm using actions > reducer > store > component approach using react redux
action.js
export const listCategoryDetails = (id) => async (dispatch) => {
try {
dispatch({ type: CATEGORY_DETAIL_REQUEST });
const { data } = await axios.get(`/api/v1/categories/nested/${id}`); // Purpose to show nested brands[]
dispatch({
type: CATEGORY_DETAIL_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: CATEGORY_DETAIL_FAIL,
payload:
error.response && error.response.data.detail
? error.response.data.detail
: error.message,
});
}
};
reducer.js
export const categoryDetailsReducer = (
state = { category: { } },
action
) => {
switch (action.type) {
case CATEGORY_DETAIL_REQUEST:
return { loading: true, ...state };
case CATEGORY_DETAIL_SUCCESS:
return { loading: false, category: action.payload };
case CATEGORY_DETAIL_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
store.js
const reducer = combineReducers({
categoryDetail: categoryDetailsReducer,
});
component
function CategoryDetail({ match, history }) {
// const { id } = useParams();
// console.log(id);
const dispatch = useDispatch();
const categoryList = useSelector((state) => state.categoryList);
const { loading, error, categories , page, pages} = categoryList;
useEffect(() => {
dispatch(listCategoryDetails());
}, [dispatch, match]);
return <div>
{categories.map(category => (
<Col key={category.id} sm={12} md={8} lg={4} xl={3} >
<h1><strong>{category.title}</strong></h1>))}
</div>;
}
export default CategoryDetail;
const id = ...
and pass it to dispatch function dispatch(listCategoryDetails(id))
Before
// const { id } = useParams();
// console.log(id);
const dispatch = useDispatch();
const categoryList = useSelector((state) => state.categoryList);
const { loading, error, categories , page, pages} = categoryList;
useEffect(() => {
dispatch(listCategoryDetails());
}, [dispatch, match]);
After
const { id } = useParams();
console.log(id);
const dispatch = useDispatch();
const categoryList = useSelector((state) => state.categoryList);
const { loading, error, categories , page, pages} = categoryList;
useEffect(() => {
dispatch(listCategoryDetails(id));
}, [dispatch, match]);
Inside UseEffect You Are Not Passing id Variable So its Saying Id Is Undefined

Categories

Resources