I want to integrate a search functionality in my Next.js app which should look like this:
User types a keyword in searchBar which is inside of Header
After clicking on the search button the keyword should be passed on the SearchResult page, in which I load it dynamically into the youtube-search-api link
The structure looks like this:
Header.js (contains SearchBar component)
_app.js (contains Header and components)
SearchResults.js (inside pages folder, should fetch typed keyword from Header)
I tried it with zustand and it looks like this currently:
Header.js:
import SearchBar from "./SearchBar";
const Header = () => {
return (
<div className={styles.header}>
...
<SearchBar />
...
</div>
);
};
export default Header;
SearchBar.js:
import create from 'zustand';
import { useRouter } from 'next/router';
import Image from 'next/image';
import styles from '../styles/Header.module.scss';
import loupe from '../public/images/loupe.png';
const useStore = create((set) => ({
keyword: '',
setKeyword: (keyword) =>
set((state) => ({
...state,
keyword,
})),
}));
const SearchBar = () => {
const router = useRouter();
const keyword = useStore((state) => state.keyword);
const setKeyword = useStore((state) => state.setKeyword);
const handleClick = (e) => {
e.preventDefault();
router.push('/searchResults');
};
return (
<div className={styles.searchBar}>
<input
type='text'
value={keyword}
placeholder='Suche...'
onChange={(e) => setKeyword(e.target.value)}
/>
<button className={styles.searchBtn} type='submit' onClick={handleClick}>
<Image src={loupe} alt='' />
</button>
</div>
);
};
export default SearchBar;
_app.js:
import Header from '../components/Header';
function MyApp({ Component, pageProps }) {
return (
<>
<Header />
<Component {...pageProps} />
</>
);
}
export default MyApp;
and SearchResults.js:
import { fetchData } from '../lib/utils';
import Moment from 'react-moment';
import { Modal } from 'react-responsive-modal';
import ReactPlayer from 'react-player/youtube';
export default function SearchResults({ videos }) {
console.log(videos);
const [modalIsOpen, setModalIsOpen] = useState(false);
const [modalData, setModalData] = useState(null);
const videoURL = 'https://www.youtube.com/watch?v=' + modalData;
const sortedVids = videos
.sort((a, b) =>
Number(
new Date(b.snippet.videoPublishedAt) -
Number(new Date(a.snippet.videoPublishedAt))
)
)
.filter((vid) => vid.snippet.title.toLowerCase());
return (
<>
<div className={`${styles.playlist_container} ${styles.search}`}>
<div className={styles.main_container}>
<h1>Search results</h1>
{sortedVids
.filter((v) => v.snippet.title !== 'Private video')
.map((vid, id) => {
return (
<div className={styles.item_container}
key={id}>
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout='fill'
objectFit='cover'
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={() => {
setModalData(vid.snippet.resourceId.videoId);
console.log(modalData);
setModalIsOpen(true);
}}
>
<Image src='/images/play.svg' width='60' height='60' />
</button>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
</div>
);
})}
</div>
</div>
<div>
<Modal
open={modalIsOpen}
onClose={() => setModalIsOpen(false)}
center
classNames={{
overlay: 'customOverlay',
modal: 'customModal',
overlayAnimationIn: 'customEnterOverlayAnimation',
overlayAnimationOut: 'customLeaveOverlayAnimation',
modalAnimationIn: 'customEnterModalAnimation',
modalAnimationOut: 'customLeaveModalAnimation',
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={videoURL}
width='100%'
height='calc(100vh - 100px)'
config={{
youtube: {
playerVars: {
autoplay: 1,
controls: 1,
},
},
}}
/>
</Modal>
</div>
<Footer />
</>
);
}
export async function getStaticProps() {
const keyword = useStore((state) => state.keyword);
const { YOUTUBE_KEY } = process.env;
const uploadsURL = `https://youtube.googleapis.com/youtube/v3/search?part=snippet&channelId=UCbqKKcML7P4b4BDhaqdh_DA&maxResults=50&key=${YOUTUBE_KEY}&q=${keyword}`;
async function getData() {
const uploadsData = fetchData(uploadsURL);
return {
videos: await uploadsData,
};
}
const { videos } = await getData();
return {
revalidate: 86400,
props: {
videos: videos.items,
},
};
}
Would someone please help me out by telling me what I did wrong and how it works in the right way? Thank you guys!!
Related
By using console.log(responseData.places) I have checked the fetching works since I am using a hook for this and seems to work fine until I setLoadedPlaces with is the method I use to update the loadedPlaces which I later use to get the values to fill the frontend part of the website.
This is the output I get from this console.log I did and the values are correct.
[{…}]
0: address: "sis se puede
busrespect: 'tu puedes',
creator: "6384e2f543f63be1c560effa"
description: "al mundial"
id: "6384e30243f63be1c560f000"
image:"https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Empire_State_Building_%28aerial_view%29.jpg/400px-Empire_State_Building_%28aerial_view%29.jpg"location: {lat: -12.086158, lng: -76.898019}
title: "Peru"
__v: 0
_id: "6384e30243f63be1c560f000"[[Prototype]]:
Objectlength: 1[[Prototype]]: Array(0)
So after this this the code I have in the frontend (SINCE the backend works properly) Let me know if you have any doubts with this logic
This is UserPlaces.js
import React, {useState, useEffect } from 'react';
import PlaceList from '../components/PlaceList';
import { useParams } from 'react-router-dom';
import { useHttpClient } from '../../shared/hooks/http-hook';
import ErrorModal from '../../shared/components/UIElements/ErrorModal';
import LoadingSpinner from '../../shared/components/UIElements/LoadingSpinner';
const UserPlaces = () => {
const {loadedPlaces, setLoadedPlaces} = useState();
const {isLoading, error, sendRequest, clearError } = useHttpClient();
const userId = useParams().userId;
useEffect(() => {
const fetchPlaces = async () => {
try {
const responseData = await sendRequest(
`http://localhost:5000/api/places/user/${userId}`
);
console.log(responseData.bus_stops)
setLoadedPlaces(responseData.bus_stops);
} catch (err) {}
};
fetchPlaces();
}, [sendRequest, userId]);
return (
<React.Fragment>
<ErrorModal error={error} onClear={clearError} />
{isLoading && (
<div className="center">
<LoadingSpinner />
</div>
)}
{!isLoading && loadedPlaces && <PlaceList items={loadedPlaces} />}
</React.Fragment>
);
};
export default UserPlaces;
This is Place-List.js
import React from 'react';
import "./PlaceList.css"
import Card from '../../shared/components/UIElements/Card'
import PlaceItem from './PlaceItem';
import Button from '../../shared/components/FormElements/Button';
const PlaceList = props => {
if (props.items.length === 0) {
return (
<div className='place-list-center'>
<Card>
<h2>No bus stops available. Be the first one to create one!</h2>
<Button to='/places/new'> Create Bus Stop </Button>
</Card>
</div>
);
}
return (
<ul className="place-list">
{props.items.map(bus_stops => (
<PlaceItem
key={bus_stops.id}
id={bus_stops.id}
image={bus_stops.image}
title={bus_stops.title}
busrespect={bus_stops.busrespect}
description={bus_stops.description}
address={bus_stops.address}
creatorId={bus_stops.creator}
coordinates={bus_stops.location}
/>
))}
</ul>
);
};
export default PlaceList;
This is PlaceItem.js
import React, { useState } from 'react';
import { useContext } from 'react';
import Card from '../../shared/components/UIElements/Card';
import Button from '../../shared/components/FormElements/Button';
import Modal from '../../shared/components/UIElements/Modal';
import Map from '../../shared/components/UIElements/Map';
import {AuthContext} from '../../shared//context/auth-context'
import "./PlaceItem.css";
const PlaceItem = props => {
const auth = useContext(AuthContext);
const [showMap, setShowMap] = useState(false);
const [showConfirmModal, setShowConfirmModal] = useState(false);
const openMapHandler = () => setShowMap(true);
const closeMapHandler = () => setShowMap(false);
const showDeleteWarningHandler = () => {
setShowConfirmModal(true);
};
const cancelDeleteHandler = () => {
setShowConfirmModal(false);
};
const confirmDeleteHandler = () => {
setShowConfirmModal(false); //when clicked close the new Modal
console.log('DELETING...');
};
return (
<React.Fragment>
<Modal show={showMap}
onCancel={closeMapHandler}
header={props.address}
contentClass="place-item__modal-content"
footerClass="place-item__modal-actions"
footer={<Button onClick={closeMapHandler}>Close </Button>}
>
<div className='map-container'>
<Map center={props.coordinates} zoom={16}/> {/* Should be props.coordinates but we writing default data for now until geocoding solved. */}
</div>
</Modal>
<Modal
show={showConfirmModal}
onCancel={cancelDeleteHandler}
header="Are you entirely sure?"
footerClass="place-item__modal-actions"
footer={
<React.Fragment>
<Button inverse onClick={cancelDeleteHandler}>
CANCEL
</Button>
<Button danger onClick={confirmDeleteHandler}>
DELETE
</Button>
</React.Fragment>
}
>
<p>
Do you want to proceed and delete this place? Please note that it
can't be undone thereafter.
</p>
</Modal>
<li className='"place=item'>
<Card className="place-item__content">
<div className='place-item__image'>
<img src={props.image} alt={props.title}/>
</div>
<div className='place-item__info'>
<h2>{props.title}</h2>
<h3>{props.address}</h3>
<p>{props.description}</p>
<p>{props.busrespect}</p>
</div>
<div className='place-item__actions'>
<Button inverse onClick={openMapHandler}> VIEW ON MAP</Button>
{auth.isLoggedIn && (<Button to={`/places/${props.id}`}> EDIT</Button> )}
{auth.isLoggedIn &&<Button danger onClick={showDeleteWarningHandler}> DELETE </Button>}
</div>
</Card>
</li>
</React.Fragment>
);
};
export default PlaceItem;
This is auth-context:
import { createContext } from "react";
export const AuthContext = createContext({
isLoggedIn: false,
userId: null,
login: () => {},
logout: () => {}});
This is is Modal.js
import React from 'react';
import ReactDOM from 'react-dom';
import Backdrop from './Backdrop';
import { CSSTransition } from 'react-transition-group';
import './Modal.css';
const ModalOverlay = props => {
const content =(
<div className={`modal ${props.className}`} style = {props.style}>
<header className={`modal__header ${props.headerClass}`}>
<h2>{props.header}</h2>
</header>
<form
onSubmit={
props.onSubmit ? props.onSubmit : event => event.preventDefault()
}
>
<div className={`modal__content ${props.contentClass}`}>
{props.children}
</div>
<footer className={`modal__content ${props.footerClass}`}>
{props.footer}
</footer>
</form>
</div>
);
return ReactDOM.createPortal(content, document.getElementById('modal-hook'));
};
const Modal = props => {
return (
<React.Fragment>
{props.show && <Backdrop onClick={props.onCancel} />}
<CSSTransition in={props.show}
mountOnEnter
unmountOnExit
timeout={200}
classNames="modal"
>
<ModalOverlay {...props}/>
</CSSTransition>
</React.Fragment>
);
};
export default Modal;
Also Trust the routing is correct since I have checked it already and I am just wondering if the logic in REACT with loadedPlaces, PlaceItema and PlaceList makes sense and it working. Let me know please. It will be really helpful.
Summary: Not getting any error but no visual data appears in the scren just the header of my website and the background (rest is empty) even though logic is functional.
const {loadedPlaces, setLoadedPlaces} = useState();
change the above line to
const [loadedPlaces, setLoadedPlaces] = useState();
I just started with React and this is my first project. I added a delete icon. I just want when press it a console log will show some text just for testing and knowing how the props are passing between components. The problem is this text is not showing in the console. Please if anyone can help with that, I would appreciate it.
I have user components, allUser component, home component which included in the app.js
User.js component
import "./User.css";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faTimes } from "#fortawesome/free-solid-svg-icons";
function User(props) {
return (
<div className="singleUser">
<div className="user">
<div>{props.id}</div>
<div>{props.name}</div>
<div>{props.phone}</div>
<div>{props.email}</div>
</div>
<div className="iconClose">
<FontAwesomeIcon icon={faTimes} onClick={() => props.onDelete} />
</div>
</div>
);
}
import User from "./user";
import { useState, useEffect } from "react";
function Allusers({ onDelete }) {
const [isLoading, setIsLoading] = useState(false);
const [actualData, setActualData] = useState([""]);
useEffect(() => {
setIsLoading(true);
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((data) => {
// const finalUsers = [];
// for (const key in data) {
// const u = {
// id: key,
// ...data[key],
// finalUsers.push(u);
// }
setIsLoading(false);
setActualData(data);
});
}, []);
if (isLoading) {
return (
<section>
<p>Loading ... </p>
</section>
);
}
return actualData.map((singlUser) => {
for (const key in singlUser) {
// console.log(singlUser.phone);
return (
<div className="userCard" key={singlUser.id}>
<User
id={singlUser.id}
name={singlUser.name}
email={singlUser.email}
phone={singlUser.phone}
key={singlUser.id}
onDelete={onDelete}
/>
</div>
);
}
});
}
export default Allusers;
import Navagation from "../components/Navagation";
import Allusers from "../components/Allusers";
import Footer from "../components/Footer";
function Home() {
const deleteHandler = () => {
console.log("something");
};
return (
<section>
<Navagation />
<Allusers onDelete={deleteHandler} />
</section>
);
}
export default Home;
You aren't actually calling the function with () => props.onDelete in User.js-- it needs to be () => props.onDelete() (note the parens added after props.onDelete).
<FontAwesomeIcon icon={faTimes} onClick={() => props.onDelete} />
...should be:
<FontAwesomeIcon icon={faTimes} onClick={() => props.onDelete()} />
I'm trying to display data from the OMdb API, but every time I try using my method nothing works.
I want to display the movie posters onto a slider using Spline.js, I was able to successfully do so whenever I manually put in the JSON data into the state but now I want to get the data from the API and I'm coming across this props.movie.map is not a function error all the way in an external component.
Heres the project on CodeSandbox just in case
https://codesandbox.io/s/github/JojoDuke/reactmoviesapp?file=/src/App.js
App.js
/* eslint-disable react-hooks/exhaustive-deps */
import React, { useState, useEffect } from 'react';
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css"
import MoviesList from "./components/MoviesList";
import ListHeading from './components/ListHeading';
import { SearchBox } from './components/SearchBox';
import AddFavourites from './components/AddFavourites';
import RemoveFavourites from './components/RemoveFavourites';
import MainMovie from './components/MainMovie';
import Navbar from './components/Navbar';
import Footer from './components/Footer';
const App = () => {
const [movies, setMovies] = useState([]);
const [searchValue, setSearchValue] = useState("");
const [favourites, setFavourites] = useState([]);
// Backup
// const getMovie = async () => {
// const url = 'http://www.omdbapi.com/?i=tt3896198&apikey=ce990560';
// const res = await fetch(url);
// const data = await res.json();
// const responseJson = JSON.parse(data);
// setMovies(responseJson);
// }
const API_KEY = "91d62f4";
const url = `http://www.omdbapi.com/?i=tt3896198&apikey=${API_KEY}`;
const getMovies = async () => {
try {
const response = await fetch(url);
const data = await response.json()
setMovies(data);
} catch (e) {
console.error(e.toString);
}
}
// FUNCTIONS
useEffect(() => {
getMovies();
}, []);
useEffect(() => {
const movieFavourites = JSON.parse(
localStorage.getItem('react-movie-app-favourites')
);
if (movieFavourites) {
setFavourites(movieFavourites);
}
}, []);
const saveToLocalStorage = (items) => {
localStorage.setItem('react-movie-app-favourites', JSON.stringify(items));
}
const addFavouriteMovie = (movie) => {
const newFavouriteList = [...favourites, movie];
setFavourites(newFavouriteList);
saveToLocalStorage(newFavouriteList);
}
const removeFavouriteMovie = (movie) => {
const newFavouriteList = favourites.filter((favourite) => favourite.imdbID !== movie.imdbID);
setFavourites(newFavouriteList);
saveToLocalStorage(newFavouriteList);
}
// FUNCTIONS CLOSE
return (
<div>
{/* Navigation Bar */}
<div>
<Navbar />
</div>
<div className="row d-flex align-items-center mb-5">
{/* Main Movie Area */}
<MainMovie/>
{/* <SearchBox
searchValue={searchValue}
setSearchValue={setSearchValue}/> */}
</div>
{/* Movies List */}
<ListHeading heading="Trending" />
<div>
<MoviesList
movies={movies}
handleFavouritesClick={addFavouriteMovie}
favouriteComponent={AddFavourites}/>
</div>
{/* List 2 */}
<div className="row d-flex align-items-center mt-4 mb-4">
<ListHeading heading="Cinetime Originals" />
</div>
<div>
<MoviesList
movies={movies}
handleFavouritesClick={addFavouriteMovie}
favouriteComponent={AddFavourites}/>
</div>
{/* List 3 */}
<div className="row d-flex align-items-center mt-4 mb-4">
<ListHeading heading="Classics" />
</div>
<div>
<MoviesList
movies={movies}
handleFavouritesClick={addFavouriteMovie}
favouriteComponent={AddFavourites}/>
</div>
<Footer />
</div>
);
};
export default App;
MoviesList.js(where I'm getting the error)
import React from 'react';
import { Splide, SplideSlide } from '#splidejs/react-splide';
//import '#splidejs/splide/dist/css/themes/splide-default.min.css';
const MoviesList = (props) => {
//const FavouriteComponent = props.favouriteComponent;
const movieSplide = props.movies.map((movie, index) => {
return(
<SplideSlide>
<div className="movie-div">
<div className="overlay"></div>
<img
className="movie-item shadow"
src={movie.Poster}
alt='movie'></img>
</div>
</SplideSlide>
);
});
return(
<Splide options={{
rewind: false,
autoWidth: true,
perPage: 6,
perMove: 2,
pagination: false,
gap: '1em',
focus: 'center',
type: 'slide',
easing: 'ease',
arrows: true
}}>
{movieSplide}
</Splide>
);
};
export default MoviesList;
I am trying to create a Carousel of images and embedded Youtube videos (the first item is a youtube video and the rest are images)
I am using the React Responsive Carusel npm package but I can't find a way to create the carousel I want without bugs.
I saw a solution over here but it's only for videos.
Here is my code at the moment:
import React from 'react'
import 'react-responsive-carousel/lib/styles/carousel.min.css' // requires a loader
import { Carousel } from 'react-responsive-carousel'
import ReactPlayer from 'react-player'
const ModalImagesPreview = () => {
return (
<div>
<Carousel>
<div>
<ReactPlayer
url='https://www.youtube.com/watch?v=ysz5S6PUM-U'
volume='1'
muted
width='100%'
playing={true}
/>
</div>
<div>
<img src='https://cdn.dribbble.com/users/2146089/screenshots/12387473/media/bf9ffb522fe68ba57ebdc62bc3f16cc5.png' />
</div>
<div>
<img src='https://cdn.dribbble.com/users/427857/screenshots/12318706/media/f30f662dbf160022412812881b2afb43.jpg' />
</div>
</Carousel>
</div>
)
}
export default ModalImagesPreview
Thanks for the helpers!
Here is what I found on the react-responsive-carousel website
import 'react-responsive-carousel/lib/styles/carousel.min.css'; // requires a loader
import React from 'react';
import ReactPlayer from 'react-player';
import { Carousel } from 'react-responsive-carousel';
import { PropTypes } from 'prop-types';
import { Grid, makeStyles } from '#material-ui/core';
const DUMMY_VIDEOS = [
{
_id: '5fd025a181e2c80897c14ae1',
videoUrl: 'https://www.youtube.com/embed/AVn-Yjr7kDc'
}
];
const useStyles = makeStyles(theme => ({
carousel: {
margin: theme.spacing(2)
}
}));
const YoutubeSlide = ({ url, isSelected }) => (
<ReactPlayer width="100%" height="276px" url={url} playing={isSelected} />
);
const CarouselVideo = ({ data }) => {
const classes = useStyles();
const customRenderItem = (item, props) => (
<item.type {...item.props} {...props} />
);
const getVideoThumb = videoId =>`https://img.youtube.com/vi/${videoId}/default.jpg`;
const getVideoId = url =>url.substr('https://www.youtube.com/watch?v='.length, url.length);
const customRenderThumb = children =>
children.map(item => {
const videoId = getVideoId(item.props.url);
return <img key={videoId} src={getVideoThumb(videoId)} />;
});
return (
<Grid item md={6} xs={12}>
<Carousel
autoPlay={false}
className={classes.carousel}
emulateTouch={true}
showArrows={true}
showThumbs={true}
showStatus={false}
infiniteLoop={true}
renderItem={customRenderItem}
renderThumbs={customRenderThumb}
>
{data.map(v => (
<YoutubeSlide
url={v.videoUrl}
muted
playing={false}
key={v._id ? v._id : v.id}
/>
))}
</Carousel>
</Grid>
);
};
YoutubeSlide.propTypes = {
url: PropTypes.string,
isSelected: PropTypes.bool
};
CarouselVideo.propTypes = {
data: PropTypes.array
};
CarouselVideo.defaultProps = {
data: DUMMY_VIDEOS
};
export default CarouselVideo;
Last step is to call this CarouselVideo where you want to render with your data as props or just call it without passint anythind => this will display the dummy videos I added there.
So you can call it like the below:
// DisplayVideo.js file with default videos as shown below
const DisplayVideo = () => {
render( <CarouselVideo />)
}
// or with your data
const DisplayVideo = ({PASS_YOU_DATA_HERE}) => {
render( <CarouselVideo data={PASS_YOU_DATA_HERE} />)
}
Result:
(source: https://www.npmjs.com/package/react-responsive-carousel)
import React, { Fragment, useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { getPosts } from '../redux/actions/#posts';
import PostItem from '../components/posts/PostItem';
import CommentForm from '../components/posts/CommentForm';
import Comment from '../components/posts/Comment';
import '../styles/posts/postComponent.scss';
const Posts = ({
getPosts,
posts: { posts, isLoading },
isAuthenticated,
user
}) => {
useEffect(() => {
getPosts();
}, []);
const [show, toggleShow] = useState(false);
console.log(show);
const postsList = isLoading ? (
<div>posts are loading</div>
) : (
posts.map(post => {
return (
<div className='post'>
<PostItem
key={post._id}
auth={isAuthenticated}
user={user}
id={post._id}
title={post.title}
body={post.text}
author={post.name}
avatar={post.avatar}
date={post.date}
likes={post.likes}
comments={post.comments.map(comment => comment)}
toggleShow={toggleShow}
show={show}
/>
<CommentForm id={post._id} />
{post.comments.map(
comment =>
show && (
<Comment
key={comment._id}
comment={comment}
auth={isAuthenticated}
admin={user}
show={show}
/>
)
)}
</div>
);
})
);
return (
<Fragment>
<Link to='/add-post'>add Post</Link>
<div>{postsList}</div>
</Fragment>
);
};
Posts.propTypes = {
getPosts: PropTypes.func.isRequired,
posts: PropTypes.object.isRequired,
isAuthenticated: PropTypes.bool.isRequired
};
const mapStateToProps = state => {
// console.log(state.posts.posts.map(post => post.likes));
// console.log(state);
return {
posts: state.posts,
isAuthenticated: state.auth.isAuthenticated,
user: state.auth.user
};
};
export default connect(mapStateToProps, { getPosts })(Posts);
import React, { Fragment } from 'react';
import '../../styles/posts/postComponent.scss';
const Comment = ({
comment: { user, avatar, name, date, text },
admin,
auth
}) => {
return (
<Fragment>
<div className='c-container'>
<div className='c-img-text'>
<img className='c-img' height={'40px'} src={avatar} />
<div className='c-nt'>
<a href='#' className='c-n'>
{name}
</a>
<span className='c-t'> {text}</span>
<i className='c-d'>{date}</i>
</div>
{auth && admin
? admin._id === user && <div className='c-toggle'>...</div>
: ''}
</div>
</div>
</Fragment>
);
};
export default Comment;
I have a list of posts stored in redux, and mapped through it to create components. Now each component has a some body and comments.
I want to show the comments only after onClick event .
Below is the code I have come up with , and on Click it is toggling all the comments of all the Components.How can I toggle comments of an individual Component.