Unexpected token in JSX when using conditional statements - reactjs

I'm trying to wrap every 3 items with a carousel component, but unfortunately as soon as I change the <p>start</p> <p>end</p> test element to the real component I get the following error:
"Unexpected token. Did you mean `{'}'}` or `&rbrace;`?",
const Alerts = (props) => {
const alerts = props.data;
let pager = 1;
return (
<ul className={styles.alerts}>
<Swiper
spaceBetween={30}
pagination={{
clickable: true,
}}
className="mySwiper"
>
{alerts.map((e, index) => (
<>
{pager % 4 === 0 || pager === 1 ? (<p>start</p>) : ""}
<div key={index} id={`alert-${index}`} className={styles.alert}>
<div className={styles.alert__content}>
<div className={styles.alert__content_top}>
<strong>
{e.token}
<a href={e.token_link}>
<i className="fa fa-external-link"></i>
</a>
</strong>
<span>{e.date}</span>
</div>
<div className={styles.alert__desc}>{e.description}</div>
</div>
<div className={styles.alert__type}>{e.type}</div>
</div>
{pager % 3 === 0 ? (<p>end</p>) : ""}
{pager === 3 ? (pager = 0) : ""}
{(pager = pager + 1)}
</>
))}
</Swiper>
</ul>
);
};
After the modification the lines looks like this:
{pager % 4 === 0 || pager === 1 ? (<SwiperSlide>) : ""}
and
{pager % 4 === 0 || pager === 1 ? (</SwiperSlide>) : ""}
What's wrong with the syntax? The numbers from the pager variable also visible on the site, maybe it's related to my syntax error?

The problem is <p>start</p> is correct JSX element. And <SwiperSlide> is just a part of element.
I'd recommend you convert your initial data array into a new array with small arrays with 3 elements in each. And go through it with two maps:
function splitToBulks(arr, bulkSize = 20) {
const bulks = [];
for (let i = 0; i < Math.ceil(arr.length / bulkSize); i++) {
bulks.push(arr.slice(i * bulkSize, (i + 1) * bulkSize));
}
return bulks;
}
const Alerts = (props) => {
const alerts = splitToBulks(props.data, 3);
let pager = 1;
return (
<ul className={styles.alerts}>
<Swiper
spaceBetween={30}
pagination={{
clickable: true,
}}
className="mySwiper"
>
{alerts.map((allerts3, index) => (
<SwiperSlide>
{allerts3.map((e, index) => (
<div key={index} id={`alert-${index}`} className={styles.alert}>
<div className={styles.alert__content}>
<div className={styles.alert__content_top}>
<strong>
{e.token}
<a href={e.token_link}>
<i className="fa fa-external-link"></i>
</a>
</strong>
<span>{e.date}</span>
</div>
<div className={styles.alert__desc}>{e.description}</div>
</div>
<div className={styles.alert__type}>{e.type}</div>
</div>
)}
</SwiperSlide>
)}
</>
))}
</Swiper>
</ul>
);
};

Related

How to improve the performance of this React 360 image?

I've made a 360 Image based on 51 images. However this is a bit slow, as it needs to do a lot of calculations for each different mouse position. I've had a different version where it changes the image src dynamically based on the mouse position and that was a bit faster, however it would request the image for every different mouse position so that would make the server a LOT slower considering it would request ~50 images/ 1-2-3 seconds from each user. In this implementation it only requests the images once when clicking on the NOT 360 image.
Only the JSX starting from ** and ending with ** is relevant.
Thank you.
const [clicked, setClicked] = useState<boolean>(false);
const [perc, setPerc] = useState<number>(0);
const [activeArray, setActiveArray] = useState<boolean[]>()
const handle360 = ():void => {
setClicked(!clicked);
var arr:boolean[] = []
for(let i=1; i<52; i++){
if(i===1){
arr.push(true)
}else{
arr.push(false);
}
}
setActiveArray(arr);
}
const [mouseX, setMouseX] = useState<number>();
const {x, setToggleRemove, toggleRemove} = useMousePosition();
useEffect(()=>{
setToggleRemove(!clicked);
}, [clicked])
const [width, setWidth] = useState<number>();
const [refX, setRefX] = useState<number>();
const [percentage, setPercentage] = useState<number>();
const [xPercentage, setXPercentage] = useState<number>();
const imageAmount = 51;
useEffect(()=>{
if(mainRef.current && refX && width){
if(x - refX <= 0 || (x-refX) >= width){
setMouseX(0);
}else{
setMouseX(x-refX);
}
}
} ,[x, mainRef])
useEffect(()=>{
if(mainRef.current){
const {x: refX, width} = mainRef.current.getBoundingClientRect();
setWidth(width);
setRefX(refX);
setPercentage(width / imageAmount | 0);
}
}, [mainRef])
useEffect(()=>{
if(mouseX){
setXPercentage(2 * mouseX / imageAmount | 0);
}
}, [mouseX])
useEffect(()=>{
if(xPercentage && xPercentage >= 1 && xPercentage <= 51){
setActiveArray((prevState) => prevState?.map((_, i) => i=== xPercentage + 1 ? true : false));
}
}, [xPercentage])
**return (
<div className="product360" ref={mainRef}>
<div className={`product360__left ${clicked ? "product360__left-360" : "product360__left-360-inactive"}`} onClick={handle360}>
{!clicked ? <><img src={product.backgroundImg + "1.jpg"} alt={""} loading={"eager"}/>
<img src={product.foregroundImg + "10.jpg"} alt={""} loading={"eager"}/></> :
activeArray ? activeArray.map((active, i)=>{
return <img key={i + 1} src={product.backgroundImg + `${i + 1}.jpg`} alt={""} loading={"eager"} className={active ? "product360__left-img-active" : "product__left-360-img-inactive"}/>
})
: ""}
{clicked ? <div className="product360__left-spinner">
<span>{perc}</span>
</div> : "" }**
</div>
{!clicked ? <div className="product360__right">
<div className="product360__right-top">
<div className="product360__right-sizes">
<span>Available Sizes</span>
<ul>
{product.sizes.map((size, i) => {
return (
<li key={i} onClick={() => handleAddSize(i)} className={selectedSize[i] ? "product360__right-sizes-selected" : ""}>{size}</li>
)
})}
</ul>
</div>
<div className="product360__right-colors">
<span>Available Colors</span>
<ul>
{product.colors.map((color, i) => {
return (
<li key={i} className={selectedColor[i] ? "product360__right-colors-selected" : ""} onClick={() => handleAddColor(i)}>{color}</li>
)
})}
</ul>
</div>
<div className="product360__right-custom">
{data ?
<>
<span>Add extra Accessories</span>
<ul>
{data.getAccessoriesBasedOnParent.map((accessory:AccessoryType, i:number)=> {
return (
<li key={i} onClick={() => handleAddAccessory(i)} className={addedAccessory ? addedAccessory[i] ? "product360__right-custom-active" : "" : ""}>
<img src={accessory.image} alt={""} loading={"lazy"}/>
<div className="product360__right-custom-info">
<span>{accessory.title}</span>
<span>${accessory.price}</span>
</div>
<div className={`product360__right-custom-checker ${addedAccessory ? addedAccessory[i] ? "product360__right-custom-checker-active" : "" : ""}`}></div>
</li>
)
})}
</ul>
</>
: ""}
</div>
<div className="product360__right-price">
<span>Total:</span> <span>${total}</span>
</div>
</div>
<div className={`product360__right-bottom ${accIndex!==undefined ? "product360__right-bottom-disabled" : ""}`}>
<span>Your custom style</span>
<div className="product360__right-bottom-info">
{file && accIndex === undefined ? <img src={URL.createObjectURL(file)} alt={"Retry"} loading="eager"/> : ""}
<div className={`product360__right-bottom-upload ${file && accIndex === undefined ? "product360__right-bottom-upload-uploaded" : ""}`}>
<label htmlFor="upload-photo">{accIndex !== undefined ? "Not available." : "Upload"}</label>
<input type="file" name="photo" multiple={false} accept="image/*" id="upload-photo" onChange={(e) => handleFileChange(e)} disabled={accIndex !== undefined ? true : false}/>
{file && accIndex === undefined ? <button type="button" onClick={()=> setFile(undefined)}>Remove</button> : ""}
</div>
</div>
</div>
</div>
:""}
<img src={"/assets/cursor/360-icon.svg"} alt={""} loading={"lazy"}/>
</div>
);
}

How can i make a counter for each component in functional component?

Halo everybody, i want to ask for my problem right now..
i want to make a counter in each component list.. i already have a function for handle the counter, but the counter doesnt increment in spesific id. that function increment the counter value for all component.. please help me
there is my code
MenuPage.js
import React, { useEffect, useState } from "react";
import "../../assets/index.css";
import ProductList from "../../components/ProductList";
import { productList } from "../../components/constant/productList";
import NavigationBottom from "../../components/NavigationBottom";
function MenuPage() {
const [showDisplay, setShowDisplay] = useState("grid");
const [quantityProduct, setQuantityProduct] = useState(0);
const handleShowDisplay = (e) => {
setShowDisplay(e);
};
const handleAdd = (value, idx) => {
if (value.id === idx + 1) {
setQuantityProduct(quantityProduct + 1);
} else {
setQuantityProduct(0);
}
};
const handleMinus = () => {
if (quantityProduct === 0) {
return 0;
}
setQuantityProduct(quantityProduct - 1);
};
return (
<div className="main_container">
<div className="container_menu__style">
<div
onClick={() => handleShowDisplay("grid")}
className="button_grid__view"
>
<i class="bi bi-grid"></i>
</div>
<div
onClick={() => handleShowDisplay("list")}
className="button_list__view"
>
<i class="bi bi-list"></i>
</div>
</div>
<div
className={` ${
showDisplay === "grid"
? "container_menu__page"
: "container_menu__page_list"
}`}
>
{productList.map((item, idx) => {
return (
<ProductList
key={idx}
id={idx}
item={item}
quantityProduct={quantityProduct}
showDisplay={showDisplay}
handleAdd={handleAdd}
handleMinus={handleMinus}
/>
);
})}
<NavigationBottom />
</div>
</div>
);
}
export default MenuPage;
ProductList.js
import React from "react";
function ProductList({
id,
item,
quantityProduct,
showDisplay,
handleAdd,
handleMinus,
}) {
return (
<div
className={` ${
showDisplay === "grid"
? "wrapper_menu__product"
: "wrapper_menu__product_list"
}`}
>
<div
className={` ${
showDisplay === "grid"
? "content_menu__product"
: "content_menu__product_list"
}`}
>
<div
className={`${
showDisplay === "grid"
? "image_menu__product"
: "image_menu__product_list"
}`}
>
<img
alt="product-list"
className={` ${showDisplay === "grid" ? "" : "img_list"}`}
src="https://i.pinimg.com/originals/23/91/52/2391523603cbd5153d7eb4e37eb3c882.png"
/>
</div>
<div className="wrapper_menu__detail">
<div className="container_menu">
<div className="menu_title__product">{item.product_name}</div>
<div className="menu_price__product">Rp. {item.product_price}</div>
</div>
<div className="container_quantity">
{/* <div className="quantity_text">Jumlah pesanan</div> */}
<button
className="button_minus__product"
onClick={() => handleMinus(item)}
>
<i class="bi bi-dash"></i>
</button>
<div className="quantity_product">{quantityProduct}</div>
<button
className="button_add__product"
onClick={() => handleAdd(item, id)}
>
<i class="bi bi-plus"></i>
</button>
</div>
{/* <div className="wrapper_quantity__product">
<div className="quantity_product__text">Jumlah Pesanan</div>
<div className="quantity_product__number"></div>
</div> */}
</div>
</div>
</div>
);
}
export default ProductList;
Your MenuPage only has a single quantityProduct (and setQuantityProduct) variable. All items are using and setting this same variable.

How can you update the props of a single element of an array using state?

I'm trying to create a component that allows a video to autoplay on mouseenter and pauses on mouseleave. However, the current code causes all videos to autoplay when you put the mouseover any single one of the videos. How can I only make the video that you're interacting with update its state in a more isolated way?
I can't seem to find a solution using React hooks anywhere, that I can understand and implement into my own code.
export default function VideoGrid(props) {
const [playing, setPlaying] = useState(false);
return (
<div>
<div className={styles.VideoGrid}>
<div className="container">
<h2 className={styles.title + " text-lg uppercase title"}>{props.title}</h2>
<div className={styles.videos}>
{props.videos ? videos.output.map((video, index) => {
return (
<div className={styles.video} key={index}>
{ video.acf.video_url ? (
<ReactPlayer
controls={false}
playing={playing}
onMouseEnter={() => setPlaying(true)}
onMouseLeave={() => setPlaying(false)}
height={205}
url={video.acf.video_url + '&showinfo=0&controls=0&autohide=1'}
width='100%'
config= {{
youtube: {
playerVars: {showinfo: 0, controls: 0}
}
}}
/>
) : (
<img src={video._embedded ? video._embedded['wp:featuredmedia'][0].media_details.sizes.full.source_url : '/logo.svg'} height={205} />
)}
<p className="mt-2">{video.title.rendered}</p>
{video.acf.description && router.pathname != '/' ? <p className={styles.description + " text-xs"}>{video.acf.description}</p> : ''}
</div>
)
}) : ''}
</div>
</div>
</div>
</div>
)
}
You can create a separate component and deal with the state individually.
const Video = (props) => {
const [playing, setPlaying] = useState(false);
return (
<div className={styles.video} key={index}>
{video.acf.video_url ? (
<ReactPlayer
controls={false}
playing={playing}
onMouseEnter={() => setPlaying(true)}
onMouseLeave={() => setPlaying(false)}
height={205}
url={video.acf.video_url + "&showinfo=0&controls=0&autohide=1"}
width="100%"
config={{
youtube: {
playerVars: { showinfo: 0, controls: 0 },
},
}}
/>
) : (
<img
src={
video._embedded
? video._embedded["wp:featuredmedia"][0].media_details.sizes.full
.source_url
: "/logo.svg"
}
height={205}
/>
)}
<p className="mt-2">{video.title.rendered}</p>
{video.acf.description && router.pathname != "/" ? (
<p className={styles.description + " text-xs"}>
{video.acf.description}
</p>
) : (
""
)}
</div>
);
};
export default Video;
Then render it in your map. You need to do the proper changes to pass your data into the video component.
export default function VideoGrid(props) {
return (
<div>
<div className={styles.VideoGrid}>
<div className="container">
<h2 className={styles.title + " text-lg uppercase title"}>
{props.title}
</h2>
<div className={styles.videos}>
{props.videos
? videos.output.map((video, index) => {
return <Video />;
})
: ""}
</div>
</div>
</div>
</div>
);
}

Render parent element over x items in n array in React?

I have a simple map function:
<div>
{
items.map((item, index)=>(
<p key={index}>{item}</p>
))
}
</div>
Which renders this HTML:
<div>
<p>1</p>
<p>2</p>
<p>3</p>
</div>
How can I insert a span over the first 2 elements so that I have?
<div>
<span>
<p>1</p>
<p>2</p>
</span>
<p>3</p>
</div>
Ive tried:
<div>
{
items.map((item, index)=>(
<>
{ index === 0 && <span> }
<p key={index}>{item}</p>
{ index === items.length - 1 && </span> }
</>
))
}
</div>
But I get an error:
Parsing error: Unexpected token
The error is due to this expressions:
// You must render children if you don't close JSX tag <span></span>
{ index === 0 && <span> }
// Same here, <span/>
{ index === items.length - 1 && </span> }
See JSX in Depth
Also, you trying to group two items under single span, doing it with a single map iteration may be over complicating things.
const items = [1, 2, 3];
const mapToParagraph = (item, index) => <p key={index}>{item}</p>;
const App = () => {
// or slice for more generics
const [first, second, ...rest] = items;
return (
<div>
<span style={{ color: `red` }}>
{[first, second].map(mapToParagraph)}
</span>
{rest.map(mapToParagraph)}
</div>
);
};
Try this, add slash at the end for span.
<div>
{[1, 2, 3, 4, 5, 6].map((item, index) => (
<>
{index === 0 && <span />}
<p key={index}>{item}</p>
{index === [1, 2, 3, 4, 5, 6].length - 1 && <span />}
</>
))}
</div>
EDITED
<div>
{
items.slice(0, 2).length > 0 && (
<span>
{ items.slice(0, 2).map((it, i) => (
<p key={i}>{it}</p>
))}
</span>
)
}
{
items.slice(2).map((it, i) => (
p>{it}</p>
))
}
</div>

How to add points dynamically like this "..." to indicates that there are more pagination buttons

I'm trying to add like this "..." in between my pagination buttons if they are more than five buttons, can any one please help me with this. this is my pagination's code:
import React, { useState } from 'react'
const Pagination = ({productsPerPage, totalPosts, paginate}) => {
const [currentPage, setCurrentPage] = useState(0)
const PageNumbers =[]
const int = Math.ceil(totalPosts / productsPerPage)
if (int === 1 ) return null
for (let i = 1; i<= int; i++) {
PageNumbers.push(i)
}
return (
<nav className="">
<ul className="pagination">
{PageNumbers.includes(currentPage - 1) &&
<a className="page-link" href="!#" onClick={() =>
{ setCurrentPage(currentPage - 1);
paginate(currentPage - 1); }}> Previous
</a>}
{PageNumbers.map(number=> (
<li key={number} className={number === currentPage ? 'page-item' : 'page-item '}>
<a onClick={ ()=> paginate(number)} href="!#" className="page-link active">
{number}
</a>
</li>
))}
{PageNumbers.includes(currentPage + 1) &&
<a className="page-link" href="!#" onClick={() =>
{setCurrentPage(currentPage + 1);
paginate(currentPage + 1); }}> Next
</a>}
</ul>
</nav>
)
}
export default Pagination
Replace your return function with below code:
return (
<nav className="">
<ul className="pagination">
{PageNumbers.map(number => (
(number < 3 || (number > currentPage-2 && number < currentPage+2) ||
number > PageNumbers.length - 2 ) ?
<li
key={number}
className={number === currentPage ? "page-item" : "page-item "}
>
<a
onClick={() => paginate(number)}
href="!#"
className={"page-link " + number ===currentPage ?'active':''}
>
{number}
</a>
</li>
:
PageNumbers.length>5 && number < 4 ? '...'
:
number < PageNumbers.length && number == currentPage+2 ? '...'
:null
))}
</ul>
</nav>
);
Above code shows first two page number, last two page number and current page number with previous page number and next page number, rest page number's will be dot dot.

Resources