Props method invoked automatically in react hooks - javascript

Hello All I am new guy working with react hooks. In the code given below I am passing my function as props and onclick it should delete the selected the id but It is getting invoked without calling it.
Here is my code:
App.js
import React, { useState } from 'react';
import './App.css';
import Keypad from './components/Keypad';
import Result from './components/Result';
import Alerts from './components/Alerts';
import ShowTickets from './components/ShowTickets';
import uuid from 'uuid';
const uuidv4 = require('uuid/v4');
function App() {
const [result, setResult] = useState('');
const [tickets, setTickets] = useState([]);
const [showMessage, setShowMessage] = useState(false);
const [message, setMessage] = useState('');
const [count, setCount] = useState(1);
const deleteTicket = id => {
console.log(id + ' from delete');
const data = tickets.filter(ticket => ticket.id !== id);
setTickets(data);
};
const randomNumber = () => {
setResult(Math.floor(100000 + Math.random() * 900000));
};
const backSpace = () => {
if (result.length !== 0) {
setResult(result.substring(0, result.length - 1));
} else {
error('Enter some number to remove');
}
};
const cb = value => {
if (result.length <= 5) {
setResult(result + value);
} else {
error('Only 6 digit tickets are allowed');
}
};
const deleteAll = ()=>{
setResult('')
}
const error = message => {
setShowMessage(true);
setMessage(message);
setTimeout(() => {
setShowMessage(false);
setMessage('');
}, 3000);
};
const addTicket = () => {
if (result !== '') {
if (count <= 5) {
if (parseInt(result) < 100000 || parseInt(result) > 999999) {
error('Value should be between 100000 & 999999');
} else {
setCount(count + 1);
const ticket = { count: count, value: result, id: uuidv4() };
setTickets(tickets => [...tickets, ticket]);
}
} else {
error('Only 5 tickets allowed');
}
} else {
error('Set the ticket id before adding ticket');
}
};
return (
<div className='ta-center'>
<center>
{showMessage ? <Alerts message={message} /> : ''}
{result !== '' ? <Result result={result} /> : ''}
<Keypad cb={cb} backSpace={backSpace} />
<button className='width' name='add' onClick={addTicket}>
<i className='fa fa-plus'></i>Add Tickets
</button>
{tickets.length ? (
<ShowTickets tickets={tickets} deleteTicket={deleteTicket} />
) : (
'No tickets to show'
)}
</center>
</div>
);
}
export default App;
Keypad.js
import React from 'react';
const Keypad = ({ cb, backSpace, deleteAll}) => {
return (
<div className='button'>
<button name='7' onClick={e => cb(e.target.name)}>
7
</button>
<button name='8' onClick={e => cb(e.target.name)}>
8
</button>
<button name='9' onClick={e => cb(e.target.name)}>
9
</button>
<br />
<button name='4' onClick={e => cb(e.target.name)}>
4
</button>
<button name='5' onClick={e => cb(e.target.name)}>
5
</button>
<button name='6' onClick={e => cb(e.target.name)}>
6
</button>
<br />
<button name='1' onClick={e => cb(e.target.name)}>
1
</button>
<button name='2' onClick={e => cb(e.target.name)}>
2
</button>
<button name='3' onClick={e => cb(e.target.name)}>
3
</button>
<br />
<button name='C' onClick={e => backSpace()}>
<i className='fa fa-arrow-left'></i>
</button>
<button name='0' onClick={e => cb(e.target.name)}>
0
</button>
<button name='CE' onClick={e => deleteAll()}>
<i className='fa fa-trash'></i>
</button>
<br />
</div>
);
};
export default Keypad;
Result.js
import React from 'react';
const Result = ({ result }) => {
return (
<div>
{result.length === '' ? (
<small>
<div className='danger'>Enter 6 digits</div>
</small>
) : (
<h3>{result}</h3>
)}
</div>
);
};
export default Result;
Alerts.js
import React from 'react';
const Alerts = ({ message }) => {
return (
<div className='alert alert-danger'>
<strong>{message}</strong>
</div>
);
};
export default Alerts;
ShowTickets.js
import React from 'react';
const ShowTickets = ({ tickets, deleteTicket }) => {
const cb = id => {
deleteTicket(id);
};
return (
<div>
Your Selected Tickets are:
{Object.entries(tickets).map(([key, val]) => (
<h2 key={key}>
<button onClick={cb(val.id)}>
ticket #{parseInt(key) + 1} {val.value}
</button>
</h2>
))}
</div>
);
};
export default ShowTickets;
Onclicking the addticket I get id in console but no ticket is displayed. If I remove deletticket from there it works fine.

In your ShowTickets.js
<button onClick={cb(val.id)}>
you are calling handler not setting it.
I believe it should be
<button onClick={() => cb(val.id)}>

Related

why every time is visit my product details page it is auto scrolling to the bottom of the page?

Whenever I'm clicking on a card to go to the product details page it is automatically going to the bottom of the next page without even scrolling it here is the sample of my code
import React from "react";
import { Link } from "react-router-dom";
import { Rating } from "#material-ui/lab";
const ProductCard = ({ product }) => {
const options = {
value: product.ratings,
readOnly: true,
precision: 0.5,
};
return (
<Link className="productCard" to={`/product/${product._id}`}>
<img src={product.images[0].url} alt={product.name} />
<p>{product.name}</p>
<div>
<Rating {...options} />
<span className="productCardSpan">
{""}({product.numOfReviews} Reviews)
</span>
</div>
<span>{`₹${product.price}/-`}</span>
</Link>
);
};
export default ProductCard;
product details page is starting from here
import React, { useEffect, useState } from "react";
import Carousel from "react-material-ui-carousel";
import "./ProductDetails.css";
import { useSelector, useDispatch } from "react-redux";
import {
clearErrors,
getProductDetails,
newReview,
} from "../../actions/productAction";
import ReviewCard from "./ReviewCard.js";
import Loader from "../layout/Loader/Loader";
import { useAlert } from "react-alert";
import MetaData from "../layout/MetaData";
import { addItemsToCart } from "../../actions/cartAction";
import {
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Button,
} from "#material-ui/core";
import { Rating } from "#material-ui/lab";
import { NEW_REVIEW_RESET } from "../../constants/productConstants";
const ProductDetails = ({ match }) => {
const dispatch = useDispatch();
const alert = useAlert();
const { product, loading, error } = useSelector(
(state) => state.productDetails
);
const { success, error: reviewError } = useSelector(
(state) => state.newReview
);
const options = {
size: "large",
value: product.ratings,
readOnly: true,
precision: 0.5,
};
const [quantity, setQuantity] = useState(1);
const [open, setOpen] = useState(false);
const [rating, setRating] = useState(0);
const [comment, setComment] = useState("");
const increaseQuantity = () => {
if (product.Stock <= quantity) return;
const qty = quantity + 1;
setQuantity(qty);
};
const decreaseQuantity = () => {
if (1 >= quantity) return;
const qty = quantity - 1;
setQuantity(qty);
};
const addToCartHandler = () => {
dispatch(addItemsToCart(match.params.id, quantity));
alert.success("Item Added To Cart");
};
const submitReviewToggle = () => {
open ? setOpen(false) : setOpen(true);
};
const reviewSubmitHandler = () => {
const myForm = new FormData();
myForm.set("rating", rating);
myForm.set("comment", comment);
myForm.set("productId", match.params.id);
dispatch(newReview(myForm));
setOpen(false);
};
useEffect(() => {
if (error) {
alert.error(error);
dispatch(clearErrors());
}
if (reviewError) {
alert.error(reviewError);
dispatch(clearErrors());
}
if (success) {
alert.success("Review Submitted Successfully");
dispatch({ type: NEW_REVIEW_RESET });
}
dispatch(getProductDetails(match.params.id));
}, [dispatch, match.params.id, error, alert, reviewError, success]);
console.log(product.images);
return (
<>
{loading ? (
<Loader />
) : (
<>
<MetaData title={`${product.name} -- ECOMMERCE`} />
<div className="ProductDetails">
<div>
{product.images &&
product.images.map((item, i) => (
<img
className="CarouselImage"
key={i}
src={item.url}
alt="product"
/>
))}
</div>
<div>
<div className="detailsBlock-1">
<h2>{product.name}</h2>
<p>Product # {product._id}</p>
</div>
<div className="detailsBlock-2">
<Rating {...options} />
<span className="detailsBlock-2-span">
{" "}
({product.numOfReviews} Reviews)
</span>
</div>
<div className="detailsBlock-3">
<h1>{`₹${product.price}`}</h1>
<div className="detailsBlock-3-1">
<div className="detailsBlock-3-1-1">
<button onClick={decreaseQuantity}>-</button>
<input readOnly type="number" value={quantity} />
<button onClick={increaseQuantity}>+</button>
</div>
<button
disabled={product.Stock < 1 ? true : false}
onClick={addToCartHandler}
>
Add to Cart
</button>
</div>
<p>
Status:
<b className={product.Stock < 1 ? "redColor" : "greenColor"}>
{product.Stock < 1 ? "OutOfStock" : "InStock"}
</b>
</p>
</div>
<div className="detailsBlock-4">
Description : <p>{product.description}</p>
</div>
<button onClick={submitReviewToggle} className="submitReview">
Submit Review
</button>
</div>
</div>
<h3 className="reviewsHeading">REVIEWS</h3>
<Dialog
aria-labelledby="simple-dialog-title"
open={open}
onClose={submitReviewToggle}
>
<DialogTitle>Submit Review</DialogTitle>
<DialogContent className="submitDialog">
<Rating
onChange={(e) => setRating(e.target.value)}
value={rating}
size="large"
/>
<textarea
className="submitDialogTextArea"
cols="30"
rows="5"
value={comment}
onChange={(e) => setComment(e.target.value)}
></textarea>
</DialogContent>
<DialogActions>
<Button onClick={submitReviewToggle} color="secondary">
Cancel
</Button>
<Button onClick={reviewSubmitHandler} color="primary">
Submit
</Button>
</DialogActions>
</Dialog>
{product.reviews && product.reviews[0] ? (
<div className="reviews">
{product.reviews &&
product.reviews.map((review) => (
<ReviewCard key={review._id} review={review} />
))}
</div>
) : (
<p className="noReviews">No Reviews Yet</p>
)}
</>
)}
</>
);
};
export default ProductDetails;
I tried linking in it but it won't work and someone told me to use useRef but i don't know how to use it
You are using React router dom. In React Router there is the problem that if we redirect to the new route, it won't automatically take you to the top of the page. Such behavior is normal when you navigate between pages.
Since you are using functional components
Try to use the following window scroll to the top when the component mounts.
useEffect(() => {
window.scrollTo(0, 0)
}, [])
Browser scroll your page.
If you don't want to let browser auto scroll your page,
use History.scrollRestoration method
Prevent automatic page location restoration
if (history.scrollRestoration) {
history.scrollRestoration = 'manual';
}
Read more at MDN History.scrollRestoration

All comment forms submit the same docId

I have a react app (a sort of twitter clone) that uses firestore for storing posts and comments on posts. Each post is rendered as an element from an array using array.map(). Each post has a comment button that opens a form to take in a comment and add it to the post. When I enter a comment and submit it, the topmost post is always the one commented on no matter which post contained the comment button that was clicked(docId for the most recently saved firestore document is always submitted by the comment button instead of the docId corresponding to that instance of the component).
The map of the posts (called "howls"):
<div className="timeline">
{sortedHowls &&
sortedHowls.map((howl) => (
<Howl
key={howl.id}
image={howl.image}
text={howl.text}
time={howl.time}
userId={howl.userId}
docId={howl.id}
comments={howl.comments}
likes={howl.likes}
/>
))}
</div>
The Howl Component looks like this:
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { useFirestoreConnect } from "react-redux-firebase";
import { firestore } from "../../../firebase-store";
// styles
import "./Howl.scss";
// components
import Avatar from "../Avatar/Avatar";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
// functions
import timeCalc from "./timeCalc";
// icons
import { faStar, faComment } from "#fortawesome/free-solid-svg-icons";
const Howl = ({ docId, userId, text, image, time, comments, likes }) => {
useFirestoreConnect([{ collection: "users" }]);
const [commenting, toggleCommenting] = useState(false);
const [newComment, setNewComment] = useState("");
const [users, setUsers] = useState(null);
const [user, setUser] = useState(null);
const getUsers = useSelector((state) => state.firestore.ordered.users);
useEffect(() => {
if (!users) {
setUsers(getUsers);
} else {
setUser(users.find((doc) => doc.uid === userId));
}
}, [users, user, userId, getUsers]);
const handleLike = () => {
const newLikesTotal = likes + 1;
firestore.collection("howls").doc(docId).update({ likes: newLikesTotal });
};
const handleComment = () => {
toggleCommenting(!commenting);
};
const handleChange = (event) => {
setNewComment(event.currentTarget.value);
};
const submitComment = (event) => {
event.preventDefault();
const { id } = event.currentTarget;
console.log(event.currentTarget);
const resetComment = () => {
toggleCommenting(!commenting);
setNewComment("");
};
if (comments) {
firestore
.collection("howls")
.doc(id)
.update({
comments: [...comments, newComment],
})
.then(() => resetComment());
} else {
firestore
.collection("howls")
.doc(id)
.update({ comments: [newComment] })
.then(() => resetComment());
}
};
return (
<div className="howl">
<div className="avatar-container">
<Avatar
photoURL={user ? user.photoURL : ""}
displayName={user ? user.displayName : ""}
/>
</div>
<div className="name-text-img-container">
<p className="userName">
{user && user.displayName} - {timeCalc(Date.now(), time)}
</p>
<p className="howl-text">{text}</p>
<div className="img-container">
{image ? (
<img src={image} alt="user uploaded" className="img" />
) : null}
</div>
<div className="buttons-container">
<form action="" className="buttons">
<label htmlFor="comment-button">
<FontAwesomeIcon icon={faComment} className="image-icon" />
</label>
<input
id="comment-button"
type="checkbox"
onClick={handleComment}
style={{ display: "none" }}
/>
<label htmlFor="like-button">
<FontAwesomeIcon icon={faStar} className="image-icon" />
</label>
<input
id="like-button"
type="checkbox"
onClick={handleLike}
style={{ display: "none" }}
/>
<label htmlFor="like-button">{likes > 0 && likes}</label>
</form>
</div>
{commenting && (
<div className="comment-form">
<form action="submit" onSubmit={submitComment} id={docId}>
<input
type="text"
name="comment-input"
className="comment-input"
maxLength={128}
onChange={handleChange}
value={newComment}
placeholder="Enter comment"
/>
<div className="buttons">
<button type="submit">Submit</button>
<button onClick={() => toggleCommenting(!commenting)}>
Cancel
</button>
</div>
</form>
</div>
)}
<div className="comments">
{comments
? comments.map((comment, index) => {
return (
<p key={index} className="comment">
{comment}
</p>
);
})
: null}
</div>
</div>
</div>
);
};
export default Howl;
How can I get the comment button to specify the correct document to update?
Link to my full repo.
It turns out that the problem is here:
<form action="" className="buttons">
<label htmlFor="comment-button">
<FontAwesomeIcon icon={faComment} className="image-icon" />
</label>
<input
id="comment-button"
type="checkbox"
onClick={handleComment}
style={{ display: "none" }}
/>
<label htmlFor="like-button">
<FontAwesomeIcon icon={faStar} className="image-icon" />
</label>
<input
id="like-button"
type="checkbox"
onClick={handleLike}
style={{ display: "none" }}
/>
<label htmlFor="like-button">{likes > 0 && likes}</label>
</form>
By using a form and inputs as the buttons instead of using <button /> elements it somehow confused react as to which instance of <Howl /> was opening the comment form and therefore which docId was sent to submitComment. Corrected <Howl /> component:
import React, { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { useFirestoreConnect } from "react-redux-firebase";
import { firestore } from "../../../firebase-store";
// components
import Avatar from "../Avatar/Avatar";
import CommentInput from "./CommentInput";
import Comment from "./Comment";
import ViewProfile from "../ViewProfile/ViewProfile";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
// functions
import timeCalc from "./timeCalc";
// styles
import "./Howl.scss";
// icons
import { faStar, faComment } from "#fortawesome/free-solid-svg-icons";
const Howl = ({ howl }) => {
useFirestoreConnect([{ collection: "users" }]);
const [commenting, toggleCommenting] = useState(false);
const [newComment, setNewComment] = useState("");
const [users, setUsers] = useState(null);
const [op, setOp] = useState(null);
const [showProfile, setShowProfile] = useState(false);
const { docId, userId, text, likes, comments, time, image } = howl;
const getUsers = useSelector((state) => state.firestore.ordered.users);
const currentUser = useSelector((state) => state.firebase.auth);
// establish user that posted this howl (op = original poster)
useEffect(() => {
users ? setOp(users.find((doc) => doc.uid === userId)) : setUsers(getUsers);
}, [users, op, userId, getUsers]);
const handleLike = () => {
const index = likes.indexOf(currentUser.uid);
let newLikes = [...likes];
if (index > 0) {
newLikes.splice(index, 1);
} else if (index === 0) {
if (likes.length > 1) {
newLikes.splice(index, 1);
} else {
newLikes = [];
}
} else {
newLikes = [...newLikes, currentUser.uid];
}
firestore.collection("howls").doc(docId).update({ likes: newLikes });
};
const handleChange = (event) => {
setNewComment(event.currentTarget.value);
};
const submitComment = (event) => {
event.preventDefault();
const { id } = event.currentTarget;
const { uid, photoURL } = currentUser;
const resetComment = () => {
toggleCommenting(!commenting);
setNewComment("");
};
firestore
.collection("howls")
.doc(id)
.update({
comments: [
...comments,
{ uid: uid, photoURL: photoURL, text: newComment },
],
})
.then(() => resetComment());
};
return (
<div className="howl">
<div className="avatar-container">
<button className="show-profile" onClick={() => setShowProfile(true)}>
<Avatar
photoURL={op ? op.photoURL : ""}
displayName={op ? op.displayName : ""}
/>
</button>
</div>
<div className="name-text-img-container">
<p className="userName">
{op && op.displayName} - {timeCalc(Date.now(), time)}
</p>
<p className="howl-text">{text}</p>
<div className="img-container">
{image && <img src={image} alt="user uploaded" className="img" />}
</div>
<div className="buttons-container">
<div className="buttons">
<button className="comment-button">
<FontAwesomeIcon
icon={faComment}
className="image-icon"
onClick={() => toggleCommenting(!commenting)}
/>
</button>
<button className="like-button" onClick={handleLike}>
<FontAwesomeIcon
icon={faStar}
className={
currentUser && likes.includes(currentUser.uid)
? "image-icon liked"
: "image-icon"
}
/>
</button>
<p>{likes.length > 0 && likes.length}</p>
</div>
</div>
{commenting && (
<CommentInput
submitComment={submitComment}
docId={docId}
toggleCommenting={toggleCommenting}
commenting={commenting}
handleChange={handleChange}
newComment={newComment}
/>
)}
{showProfile && (
<ViewProfile
user={op}
close={() => setShowProfile(false)}
update={false}
/>
)}
<div className="comments">
{comments &&
comments.map((comment, index) => {
return <Comment key={`comment${index}`} comment={comment} />;
})}
</div>
</div>
</div>
);
};
export default Howl;

Memory leak in React component whenever a delete function is run....not using useEffect?

Preview:
https://befreebucket.s3.us-east-2.amazonaws.com/beFree-5fc1c2a00cb53d0017972145-kebin1421-hotmail-com-1615773766297.gif
I currently have a Profile component acting as the Parent component; said component has the following code:
const [profile, setProfile] = useState(null)
const [posts, setPosts] = useState([])
useEffect(() => {
getProfile(match.params.id)
.then((result) => {
// Set the user
setProfile(result.payload.data)
// Get posts by user
getPosts(`?user=${match.params.id}`)
.then((result) => {
setPosts(result.payload.data)
})
.catch((err) => {
console.log('Posts error' + err)
})
})
.catch((err) => {
console.log('User error' + err)
})
}, []);
All that data is then passed into a Single component which is the children component
posts?.length > 0 ? (
posts.map((post, index) => (
<Single
key={post._id}
post={post}
postId={postId}
setObjects={setPosts}
objects={posts}
setTotalResult={setTotalResults}
/>
))
)
The problem comes when I trigger a delete function from a dynamic component within the Single component. The compoenent that contains this function looks like this in the Single component:
import React, { useEffect, useState, useContext } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
// ACTIONS
import { deletePost } from '../../../actions/post';
// HELPERS
import ConfirmModal from '../../layout/ConfirmModal';
import ContentLoader from '../../layout/ContentLoader';
import { formatDate } from '../../../helpers/utilities';
import UseImage from '../../layout/UseImage';
// REACTBOOTSTRAP
import Card from 'react-bootstrap/Card';
import Carousel from 'react-bootstrap/Carousel';
import Dropdown from 'react-bootstrap/Dropdown';
import DropdownButton from 'react-bootstrap/DropdownButton';
import Button from 'react-bootstrap/Button';
import Badge from 'react-bootstrap/Badge';
const Single = ({
deletePost,
post: {
_id,
user,
postedto,
postedfrom,
text,
images,
hidden,
likes,
sharedby,
createdAt
},
postId = null,
setObjects,
objects = [],
setTotalResults,
auth
}) => {
const hasLike = likes?.map((like) => like.user).includes(auth.user.data._id);
const hasShare = sharedby
?.map((share) => share.user)
.includes(auth.user.data._id);
const [liked, setLiked] = useState(false); // Done
const [likedIcon, setLikedIcon] = useState(`fas fa-heart`); // Done
const [likesQuantity, setLikesQuantity] = useState(0); // Done
const [, setShared] = useState(false);
const [sharedIcon, setSharedIcon] = useState(`far fa-share-square`);
const [sharesQuantity, setSharesQuantity] = useState(0);
const [hiden, setHidden] = useState(false);
const [hiddenIcon, setHiddenIcon] = useState(`fas fa-eye`);
const [, setError] = useState(false);
useEffect(() => {
setLiked(hasLike);
setLikedIcon(hasLike ? `fas fa-heart` : `far fa-heart`);
setLikesQuantity(likes?.length);
setShared(hasShare);
setSharedIcon(hasShare ? `fas fa-share-square` : `far fa-share-square`);
setSharesQuantity(sharedby?.length);
setHidden(hidden);
setHiddenIcon(hidden ? `fas fa-eye-slash` : `fas fa-eye`);
}, []);
return _id === null || _id === undefined ? (
<ContentLoader />
) : (
<article className={`${_id ? _id : postId} mb-3`}>
<Card>
<Card.Header>
<div className={``}>
<Link
to={`/profiles/${user._id ? user._id : auth.user.data._id}/posts`}
>
<UseImage
src={`${user.avatar ? user.avatar : auth.user.data.avatar}`}
alt={`${
user.username ? user.username : auth.user.data.username
}`}
classGiven={`w-auto mr-2`}
style={{
height: '35px',
objectFit: 'cover'
}}
/>
{user.username === auth.user.data.username
? 'You'
: user.username
? user.username
: auth.user.data.username}
</Link>
{postedto && (
<>
{` `}posted to{` `}
<Link
to={`/profiles/${postedto._id}/posts`}
className={`ml-1 mr-1`}
>
{postedto.username}
</Link>
</>
)}
{postedfrom && (
<>
{' '}
shared from{' '}
<Link to={`/profiles/${postedfrom._id}/posts`}>
{postedfrom.username}
</Link>
</>
)}
<div className={`float-right`}>
<DropdownButton
alignRight
variant={`secondary`}
size={`sm`}
drop={`down`}
id={`dropdown-basic-button`}
title={<i className={`fas fa-ellipsis-h`} />}
>
{user._id === auth.user.data._id && (
<>
<Dropdown.Divider />
<ConfirmModal
id={_id ? _id : postId}
action={deletePost}
classStr={`dropdown-item`}
setObjects={setObjects}
objects={objects}
setTotalResults={setTotalResults}
/>
</>
)}
</DropdownButton>
</div>
</div>
</Card.Header>
<Card.Body
className={`p-0`}
>
{images.length > 1 ? (
<>
<Carousel style={{ position: 'sticky' }}>
{images.slice(0, 5).map((image, index) => (
<Carousel.Item key={index} className={`${index}`}>
<UseImage
src={`${image}`}
alt={``}
classGiven={`p-0 d-block w-100`}
width={`auto`}
height={`auto`}
style={{ objectFit: 'fill' }}
/>
</Carousel.Item>
))}
</Carousel>
<h6 className={`position-absolute images-length-badge`}>
<Badge pill variant={`light`}>
{images.length}
</Badge>
</h6>
</>
)}
</Card.Body>
<Card.Footer className={`p-1`}>
<div className={`float-left`}>
{user._id !== auth.user.data._id && (
<Button
variant={`link`}
size={`sm`}
className={`mr-1`}
>
<i className={`${likedIcon} mr-1`} />
<span>{likesQuantity}</span>
</Button>
)}
<Link
to={`/posts/${_id ? _id : postId}`}
className={`btn btn-link btn-sm mr-1`}
>
<i className={`far fa-comment mr-1`} />
Comment
</Link>
{user._id !== auth.user.data._id && (
<Button
variant={`link`}
size={`sm`}
className={`mr-1`}
>
<i className={`${sharedIcon} mr-1`} />
<span>{sharesQuantity}</span>
</Button>
)}
</div>
<div className={`float-right`}>
{formatDate(createdAt, 'hours') + ' hours ago'}
</div>
</Card.Footer>
</Card>
</article>
);
};
Single.propTypes = {
deletePost: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired
};
const mapStateToProps = (state) => ({
auth: state.auth
});
export default connect(mapStateToProps, {
deletePost,
})(Single);
Finally, the function which triggers the memory leak in the ConfirmModal component is found under the name of deleteObject:
import React, { useState } from 'react';
// ACTIONS
// HELPERS
// REACTBOOTSTRAP
import Button from 'react-bootstrap/Button';
import Modal from 'react-bootstrap/Modal';
const ConfirmModal = ({
id = null,
sId = null,
location = ``,
as = `button`,
classStr = ``,
action,
action2,
setObjects,
objects = [],
setTotalResults
}) => {
const [confirmDeleteModal, setConfirmDeleteModal] = useState(false);
const [, setError] = useState(false);
const openDeleteModal = (e) => {
setConfirmDeleteModal(true);
};
const closeDeleteModal = (e) => {
setConfirmDeleteModal(false);
};
const deleteObject = async (e) => {
e.preventDefault();
await action(id, sId)
.then((result) => {
if (sId) {
setObjects(objects.filter((object) => object._id !== sId));
} else {
setObjects(objects.filter((object) => object._id !== id));
}
setTotalResults(objects.length - 1);
if (typeof action2 === `function`) {
action2(location)
.then((result) => {
console.log(`Done`);
})
.catch((err) => {
setError(true);
});
}
})
.catch((err) => {
setError(true);
});
};
return (
<>
<Button
variant={`danger`}
size={`sm`}
onClick={openDeleteModal}
data-target={`deleteModal#${id}`}
as={as}
className={classStr}
>
<i className={`fas fa-trash-alt mr-1`} />
Delete
</Button>
{confirmDeleteModal && (
<Modal
show={true}
onHide={closeDeleteModal}
backdrop={true}
animation={true}
size={`sm`}
id={`deleteModal#${id}`}
>
<Modal.Header closeButton>
<Modal.Title>Are you sure?</Modal.Title>
</Modal.Header>
<Modal.Body>{id}</Modal.Body>
<Modal.Footer>
<Button
variant={`secondary`}
size={`sm`}
onClick={closeDeleteModal}
>
Close
</Button>
<Button
type={`submit`}
size={`sm`}
onClick={deleteObject}
variant={`primary`}
>
Submit
</Button>
</Modal.Footer>
</Modal>
)}
</>
);
};
export default ConfirmModal;
Do anyone of you knows how to tackle this? I have been with this problem for about 3 weeks and just wanted to make sure where it came from.
Turns out, my mistake is that I forgot to type the s in the prop needed by the Single component and ConfirmModal:
posts?.length > 0 ? (
posts.map((post, index) => (
<Single
key={post._id}
post={post}
postId={postId}
setObjects={setPosts}
objects={posts}
// setTotalResult={setTotalResults}
setTotalResults={setTotalResults}
/>
))
)

if my tasks date is current then its shows task in my today task

i have todaytask on my app when i add task and date is current date then i want to show that task in today
MY ADD TASKS code:
import React, { useState } from 'react';
import uuid from 'react-uuid';
import { useSelector, useDispatch } from 'react-redux';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import database from '../firebase/firebase';
import '../App.css';
import { SingleDatePicker } from 'react-dates';
import moment from 'moment';
import 'react-dates/initialize';
import 'react-dates/lib/css/_datepicker.css';
const AddTasks = () => {
const dispatch = useDispatch();
const newLocal = null;
const [selectedDate, setSelectedDate] = useState(moment());
const [task, setTask] = useState('');
const Date = moment();
const userId = useSelector(state => state.auth.uid);
const [focused, setFoucused]= useState(false);
const addTask = () => {
console.log(userId);
console.log('addedAt');
const payload = { id: uuid(), text: task, completed: false, addedAt: JSON.stringify(selectedDate)}
const dbtasksWrapper = database.ref().child(userId).child('tasks');
return dbtasksWrapper.child(payload.id).update(payload).then(() => {
setTask('');
setSelectedDate(null);
setFoucused(false)
dispatch({ type: "ADD_TASKS", payload })
})
}
return (
<form onSubmit={e => {
e.preventDefault(e.target.value);
addTask();
} }>
<input className="input-group-prepend" value={task} placeholder="Enter your Task" onChange={e => setTask(e.target.value)} />
<SingleDatePicker
date={selectedDate}
onDateChange={date => setSelectedDate(date)}
focused={focused}
onFocusChange={ focused => setFoucused( {focused: false} )}
/>
<br/>
<input className="btn btn-primary" type='submit' value='Submit' />
</form>
);
};
export default AddTasks;
then my TASKITEMS
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import AddTasks from './AddTasks';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import database from '../firebase/firebase';
import uuid from 'react-uuid';
const TaskItem = (props) => {
const dispatch = useDispatch();
const [task, setTask] = useState(props.task);
const [index, setIndex] = useState(props.index);
const [selectedDate, setSelectedDate] = useState(null);
const [editing, setEditing] = useState(false);
const [currentTask, setCurrentTask] = useState({});
const date = new Date()
const userId = useSelector(state => state.auth.uid);
const saveTask = () => {
setEditing(false);
const payload = { id: currentTask.id, text: currentTask.text, completed: false, addedAt: selectedDate }
const dbtasksWrapper = database.ref().child(userId).child('tasks');
dbtasksWrapper.child(payload.id).update(payload).then(() => {
dispatch({ type: "ADD_TASKS", payload });
})
}
const completeTask = () => {
const payload = { id: task.id, text: task.text, completed: true, addedAt: task.addedAt }
const dbtasksWrapper = database.ref().child(userId).child('tasks');
dbtasksWrapper.child(payload.id).update(payload).then(() => {
dispatch({ type: 'COMPLETE_TASK', payload })
})
}
const removeTask = (id) => {
console.log(id);
const dbtasksWrapper = database.ref().child(userId).child('tasks');
dbtasksWrapper.child(id).remove().then(() => {
dispatch({ type: 'REMOVE_TASK', id: id })
console.log('removed');
})
}
const editTask = (task) => {
setCurrentTask(task);
setEditing(true);
}
useEffect(() => {
setTask(props.task);
setIndex(props.index);
}, [props])
return (
<li
index={index}
key={task.id}
style={{
textDecoration: !task.completed ? 'inherit' : 'line-through'
}}
>
<div>
{
!task.completed ? <p></p> : <p className="alert alert-danger" >Task Completed </p>
// <div>
// {/* {Object.values(task.completed.toString()).length } */}
// </div>
}
</div>
<div className="border">
{editing ?
<div>
<input type='text' onChange={e => setCurrentTask({ ...currentTask, text: e.target.value })} value={currentTask.text} />
<DatePicker
className="input-group-prepend"
placeholderText="Enter task date "
selected={selectedDate}
onChange={(date) => setSelectedDate(date)}
minDate={date}
/>
</div>
:
if the date is current date then this should show in todaytasks
<div>
<h3> {task.text} </h3>
<p>{task.addedAt && task.addedAt.toString()}</p>
</div>
}
{editing ?
<div>
<input type='button' className='btn btn-primary' onClick={() => saveTask(task.id)} value='Save Task' />
<input type='button' className='btn btn-link' onClick={() => setEditing(false)} value='Cancel' />
</div>
:
<div>
<input className="btn btn-info btn-sm" type='button' value='CompleteTask' onClick={() => completeTask(task.id)} />
<input className="btn btn-danger btn-sm" type='button' value='Remove Task' onClick={() => removeTask(task.id)} />
<input type='button' className="btn btn-primary" onClick={() => editTask(task)} value='Edit Task' />
</div>
}
</div>
</li>
)
}
export default TaskItem;
and my TODAYTASK;
import React from 'react';
import { useSelector } from 'react-redux';
import AddTasks from '../components/AddTasks';
import TaskItem from './TaskItem';
import Header from './Header';
i think issue with date or need to fetch data fron taskitem but i am doing that it shows blank nothing
function isToday(date) {
var currentDate = new Date();
try {
return (
date.getFullYear() === currentDate.getFullYear() &&
date.getMonth() === currentDate.getMonth() &&
date.getDate() === currentDate.getDate()
)
} catch { }
return false;
}
export default function Today() {
const tasks = useSelector(state => state.tasks);
if (tasks) {
return (
<div>
<h1>Today</h1>
<AddTasks />
{Object.values(tasks).map((task, index) => {
var isTodayTask = isToday(task.addedAt);
console.log(isTodayTask);
return (
<ul>
{isTodayTask ? (
<div>
<TaskItem
task={task}
index={index}
/>
</div>
) : (
<div>
</div>
)}
</ul>
)
})}
</div>
)
} else {
return (
<div>
<h1>Today</h1>
<AddTasks />
<div>You have no tasks</div>
</div>
)
}
}
function isToday(date) {
var currentDate = new Date();
try {
return (
date.getFullYear() === currentDate.getFullYear() &&
date.getMonth() === currentDate.getMonth() &&
date.getDate() === currentDate.getDate()
)
} catch { }
return false;
}
Do you really need to wrap the statements into try..catch block? If an error is raised here you want to know about that. I believe that the problem is indeed with your date parameter and here's why:
const Date = moment();
that is the line from your AddTasks component where you set task.addedAt prop. Moment library uses built-in Date object under the hood. Seeing that Date is a built-in JS API the Date should not be redefined which you did in your AddTasks component. I am not sure how much it impacted the whole App but that line of code along might have broken the Date object which turned moments lib inoperational. Try digging up there.
Good luck!
function isToday(date) {
const taskDate = new Date(date);
const currentDate = new Date();
its done put date in new date done the work

How to add a whole array to useState variable

I'm trying to add a whole array to useState variable
import React, { Fragment, useState, useEffect } from 'react';
import { Form, Button, Popover, OverlayTrigger } from 'react-bootstrap';
const Filter = props => {
const [formData, setFormData] = useState({
filter: ''
});
const [items, setItems] = useState([]);
const [retrievedItems, setRetrievedItems] = useState([]);
const addToFilter = newFilter => {
let retrievedFilter = ["da vinci","paris", "london"];
console.log(retrievedFilter);
if (retrievedFilter.length > 0) {
setRetrievedItems([...retrievedItems, retrievedFilter]);
retrievedFilter = 0;
setRetrievedItems([...retrievedItems, newFilter]);
} else {
setItems([...items, newFilter]);
}
console.log('items are: ', items);
console.log('retrieve filter', props.retrievedFilter);
console.log('retrieved items: ', retrievedItems);
};
useEffect(() => {
console.log('useEffect ', retrievedItems);
}, [retrievedItems]);
const deleteFilter = index => {
// props.retrievedFilter.splice(index, 1);
items.splice(index, 1);
setItems([...items]);
// setItems([...props.retrievedFilter, ...items]);
console.log(items);
};
const { filter } = formData;
const onChange = e => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const onSubmit = e => {
e.preventDefault();
addToFilter(filter);
// Passing filter data up (i.e: to components that use <Filter />)
props.filterData(filter);
//Close the Popover
document.body.click();
};
const popover = (
<Popover id="popover-basic">
<Form>
<Form.Group controlId="formGroupEmail">
<Form.Label>Add New Filter</Form.Label>
<Form.Control
type="text"
placeholder="New Filter"
name="filter"
onChange={e => onChange(e)}
/>
</Form.Group>
<Button variant="dark" type="submit" onClick={e => onSubmit(e)}>
Add
</Button>
</Form>
</Popover>
);
return (
<Fragment>
<label>
<p className="filter-title">{props.title}</p>
</label>
<div className={props.className ? props.className : 'filter'}>
{!props.retrievedFilter
? items.map((item, index) => {
return (
<div className="filter-text" key={index}>
{item}
<Button
className="filter-button"
size="sm"
onClick={() => deleteFilter(index)}
>
X
</Button>
</div>
);
})
: props.retrievedFilter.map((item, index) => {
return (
<div className="filter-text" key={index}>
{item}
<Button
className="filter-button"
size="sm"
onClick={() => deleteFilter(index)}
>
X
</Button>
</div>
);
})}
<OverlayTrigger
trigger="click"
placement="right"
rootClose
overlay={popover}
>
<p className="text-field">Type new one</p>
</OverlayTrigger>
</div>
</Fragment>
);
};
export default Filter;
however retrievedItems shows as an empty array in the console.
any help would be appreciated.
setState is async. You have to console.log inside an effect hook with the array as a parameter.
useEffect(() => console.log(retrieved_items), [ retrievedItems ])
The second parameter ensures that the effect fires in repose to a change in the values passed to it.
Per my comment, here is a code snippet that I think does what you want.
I couldn't get it running in SO but here's a codepen: https://codepen.io/anon/pen/PrYYmz?editors=1010 (watch the chrome console as you add items)
import React, {
Fragment,
useState,
useEffect
} from 'react';
const Filter = props => {
const [formData, setFormData] = useState({filter: ''});
const [items, setItems] = useState([]);
const [retrievedItems, setRetrievedItems] = useState([]);
const addToFilter = newFilter => {
let retrievedFilter = ["da vinci", "paris", "london"];
console.log('add', retrievedFilter);
if (retrievedFilter.length > 0) {
setRetrievedItems([...retrievedItems, retrievedFilter]);
retrievedFilter = 0;
setRetrievedItems([...retrievedItems, newFilter]);
} else {
setItems([...items, newFilter]);
}
console.log('items are: ', items);
console.log('retrieve filter', props.retrievedFilter);
console.log('retrieved items: ', retrievedItems);
};
useEffect(() => {
console.log('useEffect ', retrievedItems);
}, [retrievedItems]);
const deleteFilter = index => {
// props.retrievedFilter.splice(index, 1);
items.splice(index, 1);
setItems([...items]);
// setItems([...props.retrievedFilter, ...items]);
console.log(items);
};
const {filter} = formData;
const onChange = e => {
setFormData({ ...formData,
[e.target.name]: e.target.value
});
};
const onSubmit = e => {
e.preventDefault();
addToFilter(filter);
// Passing filter data up (i.e: to components that use <Filter />)
//props.filterData(filter);
//Close the Popover
document.body.click();
};
return (
<Fragment >
<label >
<p className = "filter-title" > {
props.title
} </p> </label> <
div className = {
props.className ? props.className : 'filter'
} > {!props.retrievedFilter ?
items.map((item, index) => {
return ( <
div className = "filter-text"
key = {index} > {item} <button className = "filter-button" size = "sm" onClick = {() => deleteFilter(index)}>X</button></div>
);
}) :
props.retrievedFilter.map((item, index) => {
return ( <div className = "filter-text" key = {index} > {item} <button className = "filter-button" size = "sm" onClick = {() => deleteFilter(index)} >X</button></div>);})} <input type = "text" placeholder = "New Filter" name = "filter" onChange = {e => onChange(e) }/>
<button variant = "dark" type = "submit" onClick = {e => onSubmit(e)} >Add</button>
</div>
</Fragment>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>

Categories