Passing returned data back into other components - javascript

I am looking to pass res.data back into another component. I use res.data to display results from the returned JSON into a UI.
However I would like to use res.data to conditional display certain buttons. I am using getData() to call the API.
// src/utils/debugger
let data = [];
async function getData(filter, captureName) {
if (captureName === '') {
flash('Please enter your capture name!', 5000, { color: 'red', inpType: 'danger' });
} else {
axios({
method: 'GET',
url: `http://xxx/debugger/${filter}/${captureName}/logs`,
})
.then((res) => {
if (res.data.length === 0) {
flash('No logs have been collected for this debug capture.', 5000, {
color: 'yellow',
inpType: 'warning',
});
} else {
flash('Your capture has been imported', 3000, {
color: 'green',
inpType: 'success',
});
console.log(res.data);
data = res.data;
}
return res.data;
})
.catch((err) => {
console.log(err);
});
}
}
I would like to pass res.data back into the below component so i can conditional display the buttons.
// src/component/buttons
const AllButtons = () => {
const [data, setData] = useState([]);
return (
<div>
<section id='request' className={sectionStyles}>
<div className='mt-5 inline-flex space-y-4 flex-wrap'>
<span></span>
<PrimaryBtn onClick={() => setData(adHeight())}>ad Height</PrimaryBtn>
<PrimaryBtn onClick={() => setData(adTagId())}>ad Tag Id</PrimaryBtn>
<PrimaryBtn onClick={() => setData(adWidth())}>ad Width</PrimaryBtn>
<PrimaryBtn onClick={() => setData(appBundle())}>app Bundle</PrimaryBtn>
<PrimaryBtn onClick={() => setData(appStoreUrl())}>app Store Url</PrimaryBtn>
<PrimaryBtn onClick={() => setData(askPrice())}>ask Price</PrimaryBtn>
I would like to do something like this:
// src/component/buttons
if( res.data === "someString") {
return (
<PrimaryBtn onClick={() => setData(adHeight())}>ad Height</PrimaryBtn>
<PrimaryBtn onClick={() => setData(adTagId())}>ad Tag Id</PrimaryBtn>
<PrimaryBtn onClick={() => setData(adWidth())}>ad Width</PrimaryBtn>
)
} else {
return (//something else)
}

I found it easier to use async/await with a useEffect hook,moving the flash logic inside the hook to solve this.
async function getData(filter,captureName) => {
try {
const res = await axios({
method: 'GET',
url: `http://xxx/debugger/${filter}/${captureName}/logs`,
})
return res.data
}catch(error){
throw Error(error)
}
}
const AllButtons = ({filter,captureName}) => { // assuming component receives these two props
const [data, setData] = useState([]);
useEffect(async() => {
if (captureName === '') {
flash('Please enter your capture name!', 5000, { color: 'red',
inpType: 'danger' });
}else {
try{
const response = await getData(filter, captureName) // response represents res.data
if (response.length === 0) {
flash('No logs have been collected for this debug capture.', 5000, {
color: 'yellow',
inpType: 'warning',
});
} else {
flash('Your capture has been imported', 3000, {
color: 'green',
inpType: 'success',
});
setData(response) // setting the state to be used while rendering
}
}
catch(err) {
console.log(err);
}
}
},[])
if(data === "someString") {
return (
<PrimaryBtn onClick={() => setData(adHeight())}>ad Height</PrimaryBtn>
<PrimaryBtn onClick={() => setData(adTagId())}>ad Tag Id</PrimaryBtn>
<PrimaryBtn onClick={() => setData(adWidth())}>ad Width</PrimaryBtn>
)
}else{
return (//something else)
}
}

Related

How to delete one request in react axios? [FIXED]

There is a list of notifications from the backend. Each notification has a delete button. If I click the delete button of any notification, I want that notification to be deleted.
How do I do this?
my service
const remove = (notificationDto) => {
return new Observable((observer) => { //<NotificationDto>
axiosInstance
.delete(SERVICE_PATH + '/remove', notificationDto)
.then((response) => {
observer.next(response.data);
observer.complete();
})
.catch((err) => {
console.log(err);
});
});
};
html
<div className="notificationlist__container only-desktop">
{props.notification.notificationList.map((notification) => {
return (
<div className="notificationlist__time">
{notification.notificationDay}
<div className="delete__button">
<AS.IconButton onClick={() => notificationDataUpdateDeleteClick(notification)}>
<AS.DeleteIcon />
</AS.IconButton>
</div>
</div>
);
})}
</div>
where i call the service
After sending notification as payload, the problem was solved
import { InAppNotificationsService } from 'services/InAppNotificationsService';
import { NotificationContext } from 'contexts/NotificationContext';
const { notificationData, setNotificationData } = useContext(NotificationContext);
const notificationDataUpdateDeleteClick = (notification) => {
InAppNotificationsService.remove({ data: notification }).subscribe({
next: (response) => {
InAppNotificationsService.allNotifications({ nationalId: tckn, externalContactNumber: contactInfo?.externalContactNumber }).subscribe({
next: (response) => {
setNotificationData(response);
},
error: (error) => {
console.log(error);
}
});
},
error: (error) => {
console.log(error);
}
});
};

Use Effect doesn't run on websocket ON

I am working on a websocket project in react. But when I send a message, the websocket does reload to display new messages. I have to reload my page manually to show the changes.
Here's my use Effect Hook
useEffect(() => {
if (socket.current) {
socket.current.on('msgSent', ({ newMsg }) => {
console.log('MESSAGE SENT', newMsg)
if (newMsg.receiver === openChatId.current) {
setMessages((prev) => [...prev, newMsg])
setChats((prev) => {
const previousChat = prev.find(
(chat) => chat.messagesWith === newMsg.receiver
)
previousChat.lastMessage = newMsg.msg
previousChat.date = newMsg.date
return [...prev]
})
}
})
}
}, [])
When I remove the useEffect dependency (i.e []), It works but it renders the message multiple times on the screen.
Here's the rest of my frontend client code
const openChatId = useRef('')
const auth = useContext(AuthContext)
const queryMessage = new URLSearchParams(search).get('message')
useEffect(() => {
if (!socket.current) {
socket.current = io(process.env.REACT_APP_API)
}
if (socket.current) {
socket.current.emit('join', { userId: auth.user._id })
socket.current.on('connectedUsers', ({ users }) => {
users.length > 0 && setConnectedUsers(users)
})
}
if (chats.length > 0 && !queryMessage) {
history.push(`/messages?message=${chats[0].messagesWith}`, undefined, {
shallow: true,
})
}
return () => {
if (socket.current) {
socket.current.emit('logout')
socket.current.off()
}
}
}, [chats])
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(auth.token)
}, [])
useEffect(() => {
const loadMessages = () => {
socket.current.emit('loadMessages', {
userId: auth.user._id,
messagesWith: queryMessage,
})
socket.current.on('messagesLoaded', async ({ chat }) => {
setMessages(chat.messages)
setBannerData({
firstName: chat.messagesWith.firstName,
lastName: chat.messagesWith.lastName,
profilePicUrl: chat.messagesWith.profilePicUrl,
})
openChatId.current = chat.messagesWith._id
})
socket.current.on('noChatFound', async () => {
const { firstName, lastName, profilePicUrl } = await ChatGetUserInfo(
queryMessage,
auth.token
)
setBannerData({ firstName, lastName, profilePicUrl })
setMessages([])
openChatId.current = queryMessage
})
}
if (socket.current) {
loadMessages()
}
}, [queryMessage])
const sendMsg = (msg) => {
if (socket.current) {
socket.current.emit('sendNewMsg', {
userId: auth.user._id,
msgSendToUserId: openChatId.current,
msg,
})
}
}
The backend works very well. U think my problem is with the useEffect
I fixed it. I was missing the [chats] dependency

Issue while using the Following component in React,.The User get's added to the NavBar as if it was me

Ok, this is gonna be hard to explain, but I have a bug that I don't know how to fix. I have a Follow component, where i make a call to the backend to add the user as a follower/following. The function itself works, but when I change the state of the dynamicUser, that User get's added to my navBar and I can access the Profile. I'm sharing my whole code so maybe any of you guys can point me on what is wrong. Thanks in advance!
Follow component
const Follow = ({ userId, user, setUser }) => {
const [error, setError] = useState(null);
const [follow, setFollow] = useState([]);
const classes = useStyles();
const handleFollow = (e) => {
e.preventDefault();
const accessToken = localStorage.getItem(CONST.ACCESS_TOKEN);
axios
.put(
`${CONST.SERVER_URL}${PATHS.USER}/${userId}${PATHS.FOLLOW_USER}`,
{ user },
{ headers: { authorization: accessToken } }
)
.then((response) => {
console.log("BASH", response);
setError(null);
if (!response.status) {
return setError(response);
}
setUser(response?.data);
})
.catch((error) => {
console.log("ERROR", error);
});
};
const handleUnFollow = (e) => {
e.preventDefault();
const accessToken = localStorage.getItem(CONST.ACCESS_TOKEN);
axios
.put(
`${CONST.SERVER_URL}${PATHS.USER}/${userId}${PATHS.UNFOLLOW_USER}`,
{ user },
{ headers: { authorization: accessToken } }
)
.then((response) => {
console.log("Are you?", response);
setError(null);
if (!response.status) {
return setError(response);
}
setUser(response.data);
})
.catch((error) => {
console.log(error);
});
};
return (
<div>
{user.following[0] === userId ? (
<form onSubmit={handleUnFollow}>
<Button
className={classes.unFollow}
variant="contained"
color="secondary"
type="submit"
startIcon={<PersonAddDisabledIcon />}
>
UnFollow
</Button>
</form>
) : (
<form onSubmit={handleFollow}>
<Button
className={classes.follow}
variant="contained"
color="primary"
type="submit"
startIcon={<PersonAddIcon />}
>
Follow
</Button>
</form>
)}
</div>
);
};
Parent component
const SingleUser = (props) => {
const { user, setUser } = props;
const [dynamicUser, setDynamicUser] = useState({});
const [isLoading, setIsLoading] = useState(true);
const classes = useStyles();
useEffect(() => {
setIsLoading(true);
axios
.get(`${CONST.SERVER_URL}/users/${props.match.params.userId}`, {
headers: { authorization: localStorage.getItem(CONST.ACCESS_TOKEN) },
})
.then((response) => {
setDynamicUser(response.data);
})
.catch((err) => {
console.log(err.response);
})
.finally(() => {
setIsLoading(false);
});
}, [props.match.params.userId]);
if (isLoading) {
return <LoadingComponent />;
}
console.log("DYNAMIC", dynamicUser);
return (
<div>
<Grid className={classes.button} raise elevation={3}>
<Follow userId={dynamicUser._id} user={user} setUser={setUser} />
</Grid>
)
}
this will likely either solve the issue, or make it clearer from error messages where the issue is
// ...
const Follow = ({ userId, user, setUser }) => {
const [error, setError] = useState(null);
const [follow, setFollow] = useState([]);
const classes = useStyles();
const handleFollow = () => {
return new Promise(async (resolve, reject) => {
try {
const accessToken = localStorage.getItem(CONST.ACCESS_TOKEN);
const url = `${CONST.SERVER_URL}${PATHS.USER}/${userId}${PATHS.FOLLOW_USER}`
const response = await axios.put(url, { user }, { headers: { authorization: accessToken } })
console.log("BASH", response);
setError(null);
if (!response.status) throw response
setUser(response.data);
resolve()
} catch (err) {
setError(err.response.data)
console.log("ERROR", err);
reject(err)
}
})
};
// try catch blocks are easier to troubleshoot with promises
const handleUnFollow = () => {
return new Promise(async (resolve, reject) => {
try {
const accessToken = localStorage.getItem(CONST.ACCESS_TOKEN);
const url = `${CONST.SERVER_URL}${PATHS.USER}/${userId}${PATHS.UNFOLLOW_USER}`
const response = await axios.put(url, { user }, { headers: { authorization: accessToken } })
console.log("Are you?", response);
if (!response.status) throw response
setError(null);
setUser(response.data);
resolve();
} catch (err) {
console.error(err);
setError(err.response.data);
reject(err);
}
})
};
// i made some purely syntactical changes - i've always felt this was
// more readable in my own code to wite them out this way
const hasUserId = user.following[0] === userId
return (
<div>
<form
onSubmit={async e => {
e.preventDefault();
if (hasUserId) {
await handleUnFollow()
} else {
await handleFollow()
}
}}
>
<Button
className={hasUserId ? classes.unFollow : classes.follow}
variant="contained"
color={hasUserId ? 'secondary' : 'primary'}
type="submit"
startIcon={hasUserId ? <PersonAddDisabledIcon /> : <PersonAddIcon />}
>
{hasUserId ? 'UnFollow' : 'Follow' }
</Button>
</form>
</div>
);
};
const SingleUser = (props) => {
const { user, setUser } = props;
const [dynamicUser, setDynamicUser] = useState({});
const [isLoading, setIsLoading] = useState(true);
const classes = useStyles();
useEffect(() => {
return new Promise(async (resolve, reject) => {
try {
setIsLoading(true);
const url = `${CONST.SERVER_URL}/users/${props.match.params.userId}`
const headers = { authorization: localStorage.getItem(CONST.ACCESS_TOKEN) }
const response = await axios.get(url, { headers })
setDynamicUser(response.data);
setIsLoading(false);
resolve()
} catch (err) {
console.log(err.response.data);
reject(err)
}
})
// im not sure what this part does, since useEffect is never called
// however using promises is much easier to troubleshoot bugged out code
}, [props.match.params.userId]);
if (isLoading) {
return <LoadingComponent />;
}
console.log("DYNAMIC", dynamicUser);
return (
<div>
<Grid className={classes.button} raise elevation={3}>
<Follow userId={dynamicUser._id} user={user} setUser={setUser} />
</Grid>
</div>
)
}
so I ended up fixing this, and the problem was actually on the backend, cause I was sending the wrong user, but now everything works. I'll still will put my code here cause there seem to be a problem with the unFollow.
//follow user
router.put("/:userId/follow", isLoggedIn, async (req, res) => {
try {
const user = await User.findById(req.params.userId);
const currentUser = await User.findById(req.body.user._id);
const follow = await User.findByIdAndUpdate(
currentUser,
{ $addToSet: { following: user } },
{ new: true }
);
await User.findByIdAndUpdate(user, {
$addToSet: { followers: currentUser },
});
return res.json(follow);
} catch (err) {
return res.status(500).json({ error: err });
}
});
//unFollow the user
router.put("/:userId/unFollow", isLoggedIn, async (req, res) => {
try {
const user = await User.findById(req.params.userId);
const currentUser = await User.findById(req.body.user._id);
const follow = await User.findByIdAndUpdate(
currentUser,
{ $pull: { following: user } },
{ new: true }
);
await User.findByIdAndUpdate(user, {
$pull: { followers: currentUser },
});
return res.json(follow);
} catch (err) {
return res.status(500).json({ error: err });
}
});

API request succeds but catch is executed instead of then?

I have this weird error in my React app at the moment. I am sending an api request and I want to do something if it succeeds and something else if I get an error back. The api requests succeeds, the post is getting approved, but the catch clause is executed instead of then.
Can you see something in this code that might make that happen?
The request which I am talking about is the Request.post one... the large one that ecompasses a few other requests.
export const approvePostSubmission = (post, date) => dispatch => {
const label = `${post.campaign_product_name} on ${moment(date).format('LL')}`;
if (post.post_type === 3) {
dispatch(sendGoogleEvent(GOOGLE_EVENT.STORY.APPROVE, label));
} else {
dispatch(sendGoogleEvent(GOOGLE_EVENT.POST.APPROVE, label));
}
dispatch({
type: APPROVE_POST_PENDING,
});
return Request.post(
API_ENDPOINT.POST_APPROVE(post.id),
{ publish_at: date },
false
)
.then(response => {
const { selectedContent } = store.getState().inbox;
dispatch(getUserWallet());
dispatch({
type: APPROVE_POST_SUCCESS,
});
const getPostTypeText = post_type => {
switch (post_type) {
case 3:
return 'Story';
case 4:
return 'IGTV Post';
case 5:
return 'Carousel';
case 6:
return 'IG Live';
default:
return 'Post';
}
};
const postType = getPostTypeText(selectedContent.post.post_type);
setTimeout(() => {
toast.show(
<p>
{`Woo! You approved a ${postType}! It will be published on `}
<RouterLink
to="/calendar"
color="#0dd36b"
onClick={e => toast.hide()}
>
{`${moment(date).format('LL')} 🙌`}
</RouterLink>
</p>,
{
type: 'success',
dismiss: true,
}
);
}, 100);
// Send slack bot message
Request.post(`${SLACKBOT.URL}/new-post`, {
post_status: 1,
post_type: selectedContent.post.post_type,
post_id: selectedContent.post.id,
campaign_name: selectedContent.post.campaign_product_name,
influencer_id: selectedContent.influencer.id,
influencer_name: selectedContent.influencer.full_name,
campaign_id: selectedContent.post.campaign_id,
post_image: selectedContent.post.image_url,
slack_channel: SLACKBOT.CHANNELS.NEW_POST,
})
.then(data => {})
.catch(err => console.error(err));
return response;
})
.catch(err => {
setTimeout(() => {
dispatch({
type: APPROVE_POST_FAIL_SHOW_ERR,
payload: !!err.response
? err.response.data.message
: 'Unable to approve post!',
});
!!err.response &&
toast.show(
`${err.response.data.message || err.response.data.error} 🚫`,
{ type: 'fail' }
);
setTimeout(() => {
dispatch({
type: APPROVE_POST_FAIL,
});
}, 3000);
}, 500);
});
};

Callback not working after deleting comment. REACT

I am getting the comment to delete just fine, but for some reason the callback is not being invoked. I think it could be do to how I pass multiple arguments to the function maybe, but I am not sure.
I will post the code below to help out in this problem.
Show Page:
renderCommentsButtons(comment) {
const { post, user, auth } = this.props;
if(!user) {
return (<div></div>);
}
if(auth) {
if(user._id === comment.author.id) {
return (
<div>
<button
onClick={() => this.deleteComment(comment)}
className="btn btn-xs btn-danger">
Delete
</button>
<Link
to={`/posts/${post._id}/comments/${comment._id}/edit`}
className="btn btn-xs btn-warning">
Edit
</Link>
</div>
)
}
}
}
renderComments() {
const { post } = this.props;
return post.comments.map((comment) => {
return (
<li className="list-group-item" key={comment._id}>
<div>
{comment.text} : {comment.author.email}
</div>
{this.renderCommentsButtons(comment)}
</li>
);
});
}
deleteComment(comment) {
const {id} = this.props.match.params;
const {user, post, auth} = this.props;
if(!user) {
return (<div></div>);
}
if(auth) {
if(user._id === comment.author.id){
console.log('comment_id:', comment._id, 'post_id:', post._id);
this.props.deleteComments(post._id, comment._id, () => {
this.props.history.push(`/posts/${post._id}`);
});
}
}
}
Action:
export function deleteComments(post_id, comment_id, cb) {
return function(dispatch) {
console.log('comment_id:', comment_id, 'post_id:', post_id);
axios.delete(`${ROOT_URL}/${post_id}/comments/${comment_id}`)
.then(() => {
dispatch({
type: DELETE_COMMENTS,
payload: comment_id
});
})
.then(() => cb())
.catch((error) => {
console.log(error);
});
}
}
Backend:
exports.deleteComment = function(req, res, next) {
const query = {_id: req.params.comment_id};
Comments.remove(query, function(err, comments) {
if(err) {
return next(err);
} else {
res.json(comments);
}
});
}
.then(() => { dispatch(/* action */) } ) doesn't return any promise, that's why .then(() => cb()) is not executing.
You can try to call callback just after dispatching action.
axios.delete(`${ROOT_URL}/${post_id}/comments/${comment_id}`)
.then(() => {
dispatch({ /* action */})
cb();
})
.catch((error) => {
console.log(error);
});

Categories