How to pass State in Context React and use this an another components - javascript

I am trying this code with useContext. i want to take this response.data.message in Editdata.js component. how did i do? how i will send this state message using context.
auth-context.js
const AuthContext = React.createContext({
updatePlayer: () => {},
});
export const AuthContextProvider = (props) => {
const [msg, setmsg] = useState();
const playerupdate = async (updatedPlayer) => {
const { id, player_fname, player_lname, player_nickname } = updatedPlayer;
await axios
.post(
"https://scorepad.ominfowave.com/api/adminPlayerUpdate",
JSON.stringify({ id, player_fname, player_lname, player_nickname }),
{
headers: { "Content-Type": "application/json" },
}
)
.then((response) => {
fetchPlayerList()
//navigate('/view-players');
setmsg(response.data.message)
})
.catch((error) => {
alert(error);
});
};
return (
<AuthContext.Provider
value={{
updatePlayer: playerupdate
}}
>
{props.children}
</AuthContext.Provider>
);
};
type here
Editdata.js
function Editdata() {
const authcon = useContext(AuthContext);
const submitupdateForm = (e) => {
e.preventDefault();
const playerdetail = {
player_fname: firstname,
player_lname: lastname,
player_nickname: nickname,
id: empid
}
authcon.updatePlayer(playerdetail)
}
return (
<form onSubmit={submitupdateForm}>
</form>
);
}
How is the correct way to pass state between components with useContext?

Related

Component rendering before finishing the useEffect

I have a component (ownPrescriptionsPanel) inside which I'm rendering another component (PrescriptionsList). Inside the parent component, I have a useEffect hook to fetch data using Axios for the child component (PrescriptionsList). The problem is no matter what I try, the PrescriptionsList is always empty and only gets populated when I refresh. I have three child components (all are PrescriptionsList components) but I've shown only one in the below code.
import React, { useEffect, useState } from "react";
import Axios from "axios";
import { PrescriptionsList } from "../../components/prescriptionsList/prescriptionsList";
import "./ownPrescriptionsPanelStyles.css";
export const OwnPrescriptionsPanel = () => {
const [pastPrescriptions, setPastPrescriptions] = useState([]);
const [openPrescriptions, setOpenPrescriptions] = useState([]);
const [readyPrescriptions, setReadyPrescriptions] = useState([]);
const [isBusy1, setIsBusy1] = useState(true);
useEffect(() => {
Axios.post(
"http://localhost:3001/getpatientprescriptions",
{
id: sessionStorage.getItem("id"),
},
{
headers: {
"Content-Type": "application/json",
},
}
).then((response) => {
console.log("getpatientprescriptions", response.data);
var resArr = []; //getting rid of the duplicates
response.data.filter(function (item) {
var i = resArr.findIndex(
(x) => x.prescriptionId === item.prescriptionId
);
if (i <= -1) {
resArr.push(item);
}
return null;
});
setPastPrescriptions(resArr);
setIsBusy1(false);
});
}, []);
if (isBusy1) {
return <div>loading</div>;
}
return (
<>
<PrescriptionsList
pastPrescriptions={pastPrescriptions}
heading="All prescriptions"
viewOnly={true}
prescriptionStatusOpen={false}
showPharmacy={false}
/>
</>
);
};
Edit: Given below is the code for PrescriptionList component
import React, { useState } from "react";
import Axios from "axios";
import DescriptionTwoToneIcon from "#mui/icons-material/DescriptionTwoTone";
import PresciptionModal from "../prescriptionModal/prescriptionModal";
import "./prescriptionsListStyles.css";
export const PrescriptionsList = ({
pastPrescriptions,
heading,
viewOnly,
showPharmacy,
}) => {
const [prescriptionDetails, setprescriptionDetails] = useState([]);
const [prescriptionDrugList, setPrescriptionDrugList] = useState([]);
const [open, setOpen] = useState(false);
const handleClose = () => {
console.log("close");
setOpen(false);
};
console.log("pastPrescriptions", pastPrescriptions);
const getPrescriptionDrugDetails = async (prescriptionId) => {
await Axios.post(
"http://localhost:3001/prescriptionDrugDetails",
{
prescriptionId: prescriptionId,
},
{
headers: {
"Content-Type": "application/json",
},
}
).then((response) => {
console.log("prescriptionDrugDetails", response.data);
setPrescriptionDrugList(response.data);
});
};
const handlePrescriptionClick = async (prescriptionDetails) => {
console.log("prescriptionDetails", prescriptionDetails);
setprescriptionDetails(prescriptionDetails);
await getPrescriptionDrugDetails(prescriptionDetails.prescriptionId);
setOpen(true);
};
const pastPrescriptionsList = pastPrescriptions.map((d) => (
<div
value={d}
onClick={() => handlePrescriptionClick(d)}
key={d.drugId}
className="prescriptionListItem"
>
<div style={{ width: "30px" }}>
<DescriptionTwoToneIcon fontSize="small" />
</div>
{d.prescriptionId}
</div>
));
const markPrescriptionComplete = async (d) => {
await Axios.post(
"http://localhost:3001/markcomplete",
{
prescriptionId: d.prescriptionDetails.prescriptionId,
pharmacyId: d.prescriptionDetails.pharmacyId,
},
{
headers: {
"Content-Type": "application/json",
},
}
);
console.log(
"prescriptionId, pharmacyId",
d.prescriptionDetails.prescriptionId,
d.prescriptionDetails.pharmacyId
);
window.location.reload(true);
};
return (
<div className="prescriptionsListContainer">
<div className="viewPrescriptionsLabel">{heading}</div>
<div className="prescriptionsContainer">{pastPrescriptionsList}</div>
{open && (
<PresciptionModal
open={open}
onClose={handleClose}
prescriptionDetails={prescriptionDetails}
prescriptionDrugList={prescriptionDrugList}
viewOnly={viewOnly}
// prescriptionStatusOpen={false}
markprescriptioncomplete={markPrescriptionComplete}
showPharmacy={showPharmacy}
/>
)}
</div>
);
};
I tried solution 1, solution 2 and the code shown above is using solution from geeksforgeeks. None seem to be working

How to make react component call an axios HTTP request

I am trying to make a section for my website with a news bar that contains snippets of update posts for my site. To do so, I have successfully created the data schema, routing on my backend for post and get requests. I am routing requests on the client server using axios for my XMLHTTPRequests, Redux for my global state store, and cors. Using my NewsBar component, I wrap my NewsPosts component, which is a collection of rendered NewsPost components.
NewsBar component:
function useQuery() {
return new URLSearchParams(useLocation().search);
}
const NewsBar = () => {
const classes = useStyles();
const query = useQuery();
const page = query.get('page') || 1;
const searchQuery = query.get('searchQuery');
const [currentId, setCurrentId] = useState(0);
console.log(`NewsBar: ${useLocation().search} | query=>${query}`);
console.log(`searchquery: ${searchQuery}`);
return (
<>
<Grow in>
<Grid container direction={'row'} className={classes.newsBar} justifyContent='center'>
<Typography variant='h3'>News Bar</Typography>
<Grid item>
<NewsPosts setCurrentId={setCurrentId} />
</Grid>
</Grid>
</Grow>
</>
)
}
export default NewsBar;
NewsPosts component:
const NewsPosts = ({ setCurrentId }) => {
const { newsPosts, isLoading } = useSelector((state) => state.newsPosts);
const classes = useStyles();
newsPosts.map((newsPost) => {
console.log(newsPost);
})
console.log(new Date().toISOString());
console.log(`newsPosts array: ${typeof newsPosts} ${newsPosts}`)
if (!newsPosts.length && !isLoading) return 'No news posts.';
return (
isLoading ? <LinearProgress /> : (
<Grid container alignItems='stretch' spacing={3}>
{newsPosts?.map((newsPost) => (
<Grid key={newsPost._id} item xs={12} sm={12} md={12} lg={12}>
<NewsPost newsPost={newsPost} setCurrentId={setCurrentId}/>
</Grid>
))}
</Grid>
)
);
};
export default NewsPosts;
I added console logging for each of my routing actions and methods, and unfortunately it seems as though I get an empty array of type Object instead of the page of documents I am supposed to get. Within my console, the only logs that output are from NewsPosts.js.
NewsBar: | query=>
NewsBar.js:27 searchquery: null
NewsPosts.js:17 2022-12-01T20:36:08.958Z
NewsPosts.js:18 newsPosts array: object
On top of that, I checked my network requests and none were made. Could someone attempt to tell me why this is?
Axios code as per request:
import { START_LOADING, END_LOADING, FETCH_POST, FETCH_ALL, DELETE, CREATE } from "../constants/actionTypes";
import * as api from '../api/index.js';
//CREATE ACTIONS -> should follow the standard XMLHTTPRequest operation
export const getNewsPost = (id) => async (dispatch) => {
try {
console.log('actions: action getNewsPost was called');
dispatch({ type: START_LOADING })
const { data } = await api.fetchNewsPost(id);
dispatch({type: FETCH_POST, payload: { newsPost: data }});
console.log(`got post ${data}`);
} catch (error) {
console.log(error);
}
};
export const getNewsPosts = (page) => async (dispatch) => {
try {
console.log('actions: action getNewsPosts was called');
dispatch({ type: START_LOADING });
const {data : {data, currentPage, numberOfPages }} = await api.fetchNewsPosts(page);
dispatch({ type: FETCH_ALL, payload: { data, currentPage, numberOfPages }});
dispatch({ type: END_LOADING });
} catch (error) {
console.log(error);
}
};
export const createNewsPost = (newsPost, history) => async (dispatch) => {
try {
console.log('actions: action createNewsPosts was called');
dispatch({ type: START_LOADING });
const { data } = await api.createNewsPost(newsPost);
dispatch({ type: CREATE, payload: data });
history.push(`/newsPosts/${data._id}`);
} catch (error) {
console.log(error);
}
};
export const deleteNewsPost = (id) => async (dispatch) => {
try {
console.log('actions: action deleteNewsPost was called');
await await api.deletePost(id);
dispatch({ type: DELETE, payload: id });
} catch (error) {
console.log(error);
}
};
index.js
import axios from 'axios';
const API = axios.create({ baseURL: 'http://localhost:5000' });
API.interceptors.request.use((req) => {
if (localStorage.getItem('profile')) {
req.headers.Authorization = `Bearer ${JSON.parse(localStorage.getItem('profile')).token}`;
}
return req;
});
export const fetchPost = (id) => API.get(`/posts/${id}`);
export const fetchPosts = (page) => API.get(`/posts?page=${page}`);
export const fetchPostsByCreator = (name) => API.get(`/posts/creator?name=${name}`);
export const fetchPostsBySearch = (searchQuery) => API.get(`/posts/search?searchQuery=${searchQuery.search || 'none'}&tags=${searchQuery.tags}`);
export const createPost = (newPost) => API.post('/posts', newPost);
export const likePost = (id) => API.patch(`/posts/${id}/likePost`);
export const comment = (value, id) => API.post(`/posts/${id}/commentPost`, { value });
export const updatePost = (id, updatedPost) => API.patch(`/posts/${id}`, updatedPost);
export const deletePost = (id) => API.delete(`/posts/${id}`);
export const signIn = (formData) => API.post('/user/signin', formData);
export const signUp = (formData) => API.post('/user/signup', formData);
export const fetchNewsPost = (id) => API.get(`/news/${id}`);
export const fetchNewsPosts = (page) => API.get(`/news?page=${page}`);
export const createNewsPost = (newNewsPost) => API.post('/news', newNewsPost);
export const deleteNewsPost = (id) => API.delete(`/news/${id}`);

I got a rejection error from the redux toolkit while trying to update the item

I am working on a MERN app and I have a problem when updating items. I am getting rejections when sending a patch request and there is not much info for debugging to solve the problem. I will appreciate it if someone can point out some logic that is not correct in my code. Thank you in advance.
Here below is the logic I have implemented.
postService.js:
import axios from 'axios';
const API_URL = '/api/posts/';
const updatePost = async (postId, postData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.patch(`${API_URL}/${postId}/`, postData, config);
if (response.data) {
return {
...response.data,
id: postId,
};
}
};
postSlice.js:
import { createSlice, createAsyncThunk } from '#reduxjs/toolkit';
import postService from './postService';
const initialState = {
posts: [],
isError: false,
isSuccess: false,
isLoading: false,
message: '',
};
export const updatePost = createAsyncThunk(
'posts/updatePost',
async (id, postData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await postService.updatePost(id, postData, token);
} catch (error) {
const message =
(error.response.data.message) ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
export const postSlice = createSlice({
name: 'post',
initialState,
reducers: {
reset: (state) => initialState,
},
extraReducers: (builder) => {
builder
.addCase(updatePost.pending, (state) => {
state.isLoading = true;
})
.addCase(updatePost.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.posts = state.posts.map((post) =>
post.id === action.payload.id ? action.payload : post
);
})
.addCase(updatePost.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
});
},
});
export const selectAllPosts = (state) => state.posts.posts;
export const { reset } = postSlice.actions;
export default postSlice.reducer;
Form.js:
const Form = ({ postId, setPostId }) => {
const [formData, setFormData] = useState({
postCreator: '',
title: '',
body: '',
imageFile: '',
});
const dispatch = useDispatch();
const user = JSON.parse(localStorage.getItem('user'));
const post = useSelector((state) =>
postId ? state.posts.posts.find((post) => post._id === postId) : null
);
useEffect(() => {
if (post) setFormData(post);
}, [post]);
const clearPost = () => {
setPostId(0);
setFormData({
postCreator: '',
title: '',
body: '',
imageFile: '',
});
};
const handleSubmit = async (e) => {
e.preventDefault();
if (
!formData.postCreator &&
!formData.title &&
!formData.body &&
!formData.imageFile
) {
toast.warning(
'Please fill out all fields, and make sure you are also logged in'
);
} else if (postId) {
dispatch(updatePost(postId, formData));
console.log(postId);
} else {
dispatch(createPost(formData));
clearPost();
setPostId(null);
}
clearPost();
};
The second param of createAsyncThunk is the payloadCreator.
The first param of the payloadCreator is the arguments. The second param of payloadCreator is thunkAPI.
So you should combine id and postData into a single object to represent the arguments.
Update postSlice.js:
export const updatePost = createAsyncThunk(
'posts/updatePost',
async ({id, postData}, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await postService.updatePost(id, postData, token);
} catch (error) {
const message =
(error.response.data.message) ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
Update where you dispatch the updatePost thunk:
updatePost({
id: 123,
postData: {
foo: 'bar'
}
})

ReactJS: Unable to retrieve properly localStorageItem after navigate to another component

I have this scenario that is after the user login and assuming it is success, user details / user token is stored to localStorage and will automatically navigate to dashboard page, dashboard page has some api calls and those api calls required/needs token that is stored in the localStorage, my problem is that it is unable to retrieve those values in localStorage, but when I check from localStorage using console, the key/value is there, I noticed that, I need to refresh the page to retrieve those details without a problem. How can I possibly fix this issue? to be able to get localStorage value after navigating to another component?
Here is my code for index.tsx
ReactDOM.render(
<AuthContextProvider>
<App />
</AuthContextProvider>,
document.getElementById("root")
);
AuthContext code:
const AuthContext = React.createContext({
user: "",
isLoggedIn: false,
login: (userdata: any, expirationTime: string) => {},
logout: () => {},
});
export const AuthContextProvider = (props: any) => {
const initialUser = localStorage.getItem("user") || "";
const [userData, setUserData] = useState(initialUser);
const userIsLoggedIn = !!userData;
const logoutHandler = () => {
setUserData("");
localStorage.removeItem("user");
};
const loginHandler = async (
user: any,
expirationTime: string
) => {
localStorage.setItem("user", JSON.stringify(user));
setUserData(user);
};
const contextValue = {
user: userData,
isLoggedIn: userIsLoggedIn,
login: loginHandler,
logout: logoutHandler,
};
return (
<AuthContext.Provider value={contextValue}>
{props.children}
</AuthContext.Provider>
);
};
export default AuthContext;
App.tsx code
function App() {
const authCtx = useContext(AuthContext);
return (
<BrowserRouter>
<Routes>
{!authCtx.isLoggedIn && (
<Route element={<LoginLayout />}>
<Route index element={<SignInForm />} />
{/*Other links here */}
</Route>
)}
{authCtx.isLoggedIn && (
<Route element={<AdminLayout />}>
<Route path="dashboard" element={<DashboardScreen />} />
{/*Other links here */}
</Route>
)}
<Route path="*" element={<PageNotFound />} />
</Routes>
</BrowserRouter>
);
}
Login code:
try {
await AuthService.login(email, password).then(
(res) => {
authCtx.login(res, "0");
navigate("../dashboard", { replace: true });
},
(error) => {
}
);
} catch (err) {
console.log(err);
}
Dashboard code:
const loadCountOnlineUsers = useCallback(async () => {
try {
await DashboardService.loadCountOnlineUsers().then(
(res) => {
setCntOnlineUsers(res.count);
setflagOnlineUsers(false);
},
(error) => {
setflagOnlineUsers(false);
}
);
} catch (err) {
console.log(err);
setflagOnlineUsers(false);
}
}, [setCntOnlineUsers, setflagOnlineUsers]);
useEffect(() => {
loadCountOnlineUsers();
}, [loadCountOnlineUsers]);
Dashboard service code:
const config = {
headers: {
"Content-Type": "application/json",
Authorization: AuthHeader(),
},
params: {},
};
const loadCountOnlineUsers = () => {
config["params"] = {};
return axios
.get(API_URL + "api/v1/dashboard-related/online-users", config)
.then((response) => {
return response.data;
});
};
const DashboardService = {
loadCountOnlineUsers,
};
export default DashboardService;
Auth-header code:
export default function AuthHeader() {
const user = JSON.parse(localStorage.getItem("user") || "{}");
if (user && user.token) {
return "Bearer " + user.token;
} else {
return "";
}
}
The problem is that the check to localStorage in AuthHeader() isn't updating reactively. The fix would be to rewrite AuthHeader to accept the user data like this:
export default function AuthHeader(user) {
const user = JSON.parse(user || "{}");
if (user && user.token) {
return "Bearer " + user.token;
} else {
return "";
}
}
and then continue the data piping into the area where AuthHeader() is called, perhaps like this:
const config = (user) => ({
headers: {
"Content-Type": "application/json",
Authorization: AuthHeader(),
},
params: {},
});
const loadCountOnlineUsers = (user) => {
config["params"] = {};
return axios
.get(API_URL + "api/v1/dashboard-related/online-users", config(user))
.then((response) => {
return response.data;
});
};
const DashboardService = {
loadCountOnlineUsers,
};
Lastly, using an effect in the dashboard to update it reactively, while connecting to context:
const authCtx = useContext(AuthContext);
const user = authCtx.user;
const loadCountOnlineUsers = (user) => {
return useCallback(async () => {
try {
await DashboardService.loadCountOnlineUsers(user).then(
(res) => {
setCntOnlineUsers(res.count);
setflagOnlineUsers(false);
},
(error) => {
setflagOnlineUsers(false);
}
);
} catch (err) {
console.log(err);
setflagOnlineUsers(false);
}
}, [setCntOnlineUsers, setflagOnlineUsers]);
}
useEffect(() => {
loadCountOnlineUsers(user);
}, [loadCountOnlineUsers, user]);

Can not navigate to another pages after login

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)

Categories

Resources