When i am dispatching startAddLike , I am getting undefined value of uid in the server side ie. req.body.uid = undefined.how to solve it?
Action generator:
export const startAddLike = (id) => {
return (dispatch, getState) => {
const uid = getState().auth.uid;
axios
.post(`http://localhost:5000/api/posts/${id}/like`, uid)
.then(res => dispatch(likePost(id, uid)))
}
}
Like Post Route
router.post('/:id/like', (req, res) => {
console.log(req.body.uid);
Post.findOneAndUpdate({_id:req.params.id}, {$push: {likes: req.body.uid}},{ "new": true})
.then(post => {
console.log('l'+post);
res.json(post);
})
});
In here uid should be passed as an object.
So this should be
export const startAddLike = (id) => {
return (dispatch, getState) => {
const uid = getState().auth.uid;
axios
.post(`http://localhost:5000/api/posts/${id}/like`, { uid: uid })
.then(res => dispatch(likePost(id, uid)))
}
}
Hope that fixes your issue.
Related
I am new to websockets and socket.io. I have a few challenges>
I have developed the application with react and nodejs using socket.io.
useEffect(() => {
const getAllChats = async (token) => {
try {
setLoading(true)
const res = await getChats(token)
if (res) {
setChats(res)
setLoading(false)
}
} catch (err) {
console.log(err)
setLoading(false)
}
}
getAllChats(user.token)
}, [])
export const getChats = (token) => {
return request(`/api/v1/chats`, {
token,
method: 'GET',
})
}
The above code is used to fetch the chat from the backend.
At the backend, I have the code:
exports.getAllChats = catchAsync(async (req, res, next) => {
const user = await Chat.findOne({ user: req.user._id }).populate(
'chats.messagesWith'
)
let chatsToBeSent = []
if (user.chats.length > 0) {
chatsToBeSent = await user.chats.map((chat) => ({
messagesWith: chat.messagesWith._id,
firstName: chat.messagesWith.firstName,
lastName: chat.messagesWith.lastName,
profilePicUrl: chat.messagesWith.profilePicUrl,
lastMessage: chat.messages[chat.messages.length - 1].msg,
date: chat.messages[chat.messages.length - 1].date,
}))
}
return res.json(chatsToBeSent)
})
How can I make new messages remain at the top of the list? Presently, It is always ordered by created date
My state looks like:
const [profileList, setProfileList] = useState([]);
function looks like:
const getFriends = async () => {
await axios
.get(APICallString + id)
.then((response) => {
(async () => {
let p = [];
for await (const e of response.data) {
axios
.get(
"http://localhost:3002/persons/getById/" +
e.friendId
)
.then((response) => {
p.push(response.data);
})
.catch((error) => {
console.log(error);
});
}
console.log(p);
setProfileList(p);
})();
})
.catch((error) => {
errMsg = error.message;
console.log(error);
});
setLoaded(true);
};
Button:
<Button className="p-2 border" onClick={() => getFriends()}>
Search
</Button>
The function works as expected, when I change state by typing in my textbox... but it doesnt change state its self.
Why?
I need to reset global variable on custom hook when unit testing React component. I have read few tutorials and StackOverflow answers to this simple task, but without luck to implement it correctly.
The problem
userInfo is undefined in the first and second test but when runs the third test userInfo is defined then on useEffect doesn't change the value... So my question is how to reset userInfo for each test.
jest.resetModules // doesn't work
jest.isolateModules // doesn't work
My simplest possible setup for single test is as following:
My Environment
"jest": "^24.9.0",
My Hook
import {useState, useEffect} from "react";
// This variable is an object save user info
let userInfo = null;
export default (authService) => {
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (userInfo !== null || authService === null) {
return;
}
setLoading(true);
authService
?.getUser()
.then((response) => {
userInfo = {owners: [{...response, cost_center: response.costCenter || "N/A"}]};
})
.catch(() => {
setError({
title: "authService Error",
message: "Error getting user",
status: 500
});
})
.finally(() => setLoading(false));
}, [authService]);
return [userInfo, error, loading];
};
My Test
import {renderHook} from "#testing-library/react-hooks";
import * as sinon from "sinon";
import {getSpyOfUseOktaAuth} from "../../../__tests__/";
import {Info, InfoFromRequest, InfoWithNoCostCenter} from "../../../__tests__/";
describe("useGetUserInfo", () => {
let clock;
beforeEach(() => {
clock = sinon.useFakeTimers();
jest.useFakeTimers();
});
afterAll(() => {
clock.restore();
});
it("should set the error value after the getUserInfo function throws an error", async () => {
const useGetUserInfo = require("../index").default;
const errorMessage = {
title: "authService Error",
message: "Error getting user from",
status: 500
};
const getAuthMock = getSpyOfUseAuth({
Auth: {
signOut: jest.fn(),
getUser: jest.fn(async () => {
throw new Error("Auth Error");
})
},
authState: {}
});
const {result, rerender, waitForNextUpdate} = renderHook(() =>
useGetUserInfo(getAuthMock.results.Auth)
);
rerender();
await waitForNextUpdate();
expect(result.current[1]).toEqual(errorMessage);
getAuthMock.instance.mockRestore();
});
it("should return the user info from after run the getUserInfo function", async () => {
const useGetUserInfo = require("../index").default;
let authService = null;
const {result, rerender, waitForNextUpdate} = renderHook(() => useGetOktaUserInfo(authService));
const getAuthMock = getSpyOfUseAuth({
Auth: {
signOut: jest.fn(),
getUser: jest.fn(async () => Info)
},
authState: {}
});
authService = getAuthMock.results.Auth;
rerender();
await waitForNextUpdate();
expect(result.current[0]).toEqual(InfoFromRequest);
getAuthMock.instance.mockRestore();
});
it("should set cost_center as in data as N/A if costCenter is not defined in user info ", async () => {
const useGetUserInfo = require("../index").default;
const getAuthMock = getSpyOfUseAuth({
Auth: {
signOut: jest.fn(),
getUser: jest.fn(async () => InfoWithNoCostCenter)
},
authState: {}
});
const {result, rerender} = renderHook(() => useGetUserInfo(getAuthMock.results.Auth));
rerender();
expect(result.current[0].owners[0].cost_center).toEqual("N/A");
getAuthMock.instance.mockRestore();
});
});
I would say that either you export the 'userInfo' variable from the hook and you set it to null manually before each test, or you treat 'userInfo' as a state variable just like 'error' and 'loading'
If you go for the first option, you will need to export by reference Node Modules - exporting a variable versus exporting functions that reference it?
For the second option, it would be something like this
import {useState, useEffect} from "react";
export default (authService) => {
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [userInfo, setUserInfo] = useState(null);
useEffect(() => {
if (userInfo !== null || authService === null) {
return;
}
setLoading(true);
authService
?.getUser()
.then((response) => {
setUserInfo({owners: [{...response, cost_center: response.costCenter || "N/A"}]});
})
.catch(() => {
setError({
title: "authService Error",
message: "Error getting user",
status: 500
});
})
.finally(() => setLoading(false));
}, [authService]);
return [userInfo, error, loading];
};
The solution I got is to separate each case into different files. As jest load each file in a different process, this will be enough
LocalStorage somehow doesn't want to stay updated on refresh page. I'm not sure why is that happening, and where is my mistake. The backend is updating fine but the localStorage doesn't stay updated.
Here is where I'm updating localStorage:
const UserContextProvider = (props) => {
const [user, setUser] = useState({})
const [cart, setCart] = useState(localStorage.getItem("cart") || [])
useEffect(() => {
fetch(`${API}/auth/user`, {
method: 'GET',
withCredentials: true,
credentials: 'include'
})
.then (response => response.json())
.then (response => {
setUser(response.user)
})
.catch (error => {
console.error (error);
});
}, [setUser])
useEffect(() => {
localStorage.setItem("cart", JSON.stringify(user.cart))
}, [setUser])
const addToCart = (user, product) => {
fetch(`${API}/cart/usercart`, {
method:"POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify([user._id, product])
})
.then(() => setUser({...user, cart: [...user.cart, product]}))
.catch(error => console.log(error))
}
return (
<UserProvider value={[user, setUser, addToCart, cart]}>
{props.children}
</UserProvider>
)
}
export default UserContextProvider;
And here is the component where I'm trying to use it:
const Cart = props => {
const [user, setUser, cart] = useContext(UserContext)
...
{cart?.length === 0 ? <></> :
<>
{cart?.map(product => {
return(...)
The following code only runs once when the component mounts:
useEffect(() => {
setCart(JSON.parse(localStorage.getItem("cart")) || [])
}, []);
In order to render the latest value you'll have to depend on a prop or something that updates when cart updates:
useEffect(() => {
setCart(JSON.parse(localStorage.getItem("cart")) || [])
}, [props.something]);
Based on your implementation, I'd recommend having your contextProvider provide this data instead of component itself retrieving it from localStorage on each render. You only need the localStorage value when the app starts.
I'm trying to find a way to update my "user" state, but I'm stuck here for 3 days already, I need some help.
Here is my user context:
import React, {useEffect, useState} from 'react';
export const UserContext = React.createContext({})
const UserProvider = UserContext.Provider;
const UserContextProvider = (props) => {
const [user, setUser] = useState({})
useEffect(() => {
fetch(`${API}/auth/user`, {
method: 'GET',
withCredentials: true,
credentials: 'include'
})
.then (response => response.json())
.then (response => {
setUser(response.user)
})
.catch (error => {
console.error (error);
});
}, [setUser])
console.log(user)
return (
<UserProvider value={{user, setUser}}>
{props.children}
</UserProvider>
)
}
export default UserContextProvider;
Here is where I'm trying to update the user. In my case I'm trying to push an object in user.cart array, cuz everything on the back-end is fine, but in the front-end the state is not updating:
First I'm using the UserContext:
const Products = () => {
const {user, setUser} = useContext(UserContext) ...
And then here I'm trying to update the user state, BUT when I click the button it logged me out:
<button className="addTo--Cart--Button--Container">
<FaShoppingCart onClick={() => {addToCart(user._id, product); setUser(oldState => oldState.cart.push(product))}}/>
</button>
After this logged me out, the console.log(user) which is in UserContextProvider function log only the user.cart updated lenght.
AND one more:
How to remove item from context:
Here is my remove function:
const removeFromContextCart = (id) => {
console.log(id)
const updatedCart = user.cart.filter((item) => item.id !== id);
setUser(oldState => ({
...oldState,
cart: [
...oldState.cart,
updatedCart
]
}))
}
And my button:
<button className="remove--Button" onClick={() => {removeFromCart(user._id, product); setUser(removeFromContextCart(product._id))}}> REMOVE</button>
Try updating the user state in this way
setUser(oldState => ({
...oldState,
cart: [
...oldState.cart,
product
]
}))