how to render divs dynamically based on the number of items - reactjs

I want to show slideshow circle buttons dynamically based on the number of slides I will get from the server. I couldn't do it with loops since I have a number of slides predefined & no array. How can I show my buttons? Now I manually created 4 buttons. (I deleted unnecessary code so that only important snippets are present).
import React = require("react");
type NavigationEvent = "Backward" | "Forward" | "Pause" | "Play";
interface Props {
slidesAmount: number;
activeSlideIndex: number;
}
function SlideshowCarouselNavigationBarComponent(props: Props) {
const onPlayButtonClicked = () => {
props.navigate("Play");
}
const onPauseButtonClicked = () => {
props.navigate("Pause");
}
const onSlideButtonClicked = index => {
props.navigateToIndex(index);
}
return (
<div>
<div>
<div className={classes.dotsContainer}>
<div className={classes.dots}>
</div>
<div className={classes.dots}>
</div>
<div className={classes.dots}>
</div>
<div className={classes.dots}>
</div>
</div>
</div>
</div>
)
}
export = SlideshowCarouselNavigationBarComponent;

You can do the following (it is the most concise and understable way that I found out) : Iterating slidesAmount times, in order to display the circles:
<div className={classes.dotsContainer}>
{[...Array(props.slidesAmmount)].map((_)=>(
<div className={classes.dots}>
</div>
))}
</div>

You can use Array.fill() This will create array of preidentified length filled with unidentified values
new Array(props.slidesAmmount).fill().map((v, i){
return <div> .... </div>
});
please see How to create an array containing 1...N for more detailed answers

Related

Filtered products don't appear on the first page after pagination in Reactjs

Basically, after filtering through a set of products, depending on the current page I am on, I get demonstrated with the corresponding product cards. However, a problem occurs: after filtering, the selected products don't show up on the first page, but on the second page while the first has nothing there.
For example, I have two categories of products: "Hi, World" and "Horoscope". If I select both, everything works perfectly fine and I get all the products well-paginated, with "Hi, World" appearing on the first page and followed by "Horoscope" products on the second page. But, if I only want to select "Horoscope", the products don't appear on the first page, but on the second page.
Product showcasing page:
{/*pagination setting: I divide the products into 10 for each page and so for the first page, only products at index 0 to 10 get demonstrated and the logic follows for the other pages*/}
const [currentPage,setCurrentPage]=useState<number>(1);
const [postsPerPage,setPostsPerPage]=useState<number>(10);
const indexOfLastPost=currentPage*postsPerPage;
const indexOfFirstPost=indexOfLastPost-postsPerPage;
{/*product array getting paginated/sliced*/}
{
(productData?.map((product)=>{
if(product.theme=== "Horoscope"&&horoscopeFilter){
currentProductRendered.push(product);
return(
<ProductCard productData={product} setAddToShoppingCartStatus={setAddToShoppingCartStatus} setShoppingCartIsClicked={setShoppingCartIsClicked}/>
)
}else if(product.theme==="Hi, World"&&hiWorldFilter){
currentProductRendered.push(product);
return(
<ProductCard productData={product} setAddToShoppingCartStatus={setAddToShoppingCartStatus} setShoppingCartIsClicked={setShoppingCartIsClicked}/>
)
}
else{
return;
}
}).slice(indexOfFirstPost,indexOfLastPost)
)
}
{/*Pagination component*/}
<Pagination postsPerPage={postsPerPage} totalPosts={currentProductRendered?.length as number} currentPage={currentPage} setCurrentPage={setCurrentPage}></Pagination>
Pagination component:
type Props={
postsPerPage: number;
totalPosts:number;
currentPage:number;
setCurrentPage:(currentPage:number)=>void;
}
export default function Pagination(props:Props){
const pageNumbers=[];
for(let i=1;i<=Math.ceil(props.totalPosts/props.postsPerPage);i++){
pageNumbers.push(i);
}
const handlePrevOnClick=()=>{
let currentPage=props.currentPage;
props.setCurrentPage(currentPage-1);
}
const handleNextOnClick=()=>{
let currentPage=props.currentPage;
props.setCurrentPage(currentPage+1);
}
let tempPageNumbers:(number | string)[];
{/*depending on the length of pageNumbers, pagination numbers get shown visually accordingly*/}
if(pageNumbers.length===1){
tempPageNumbers=[1];
}else if(pageNumbers.length===2){
tempPageNumbers=[1,2];
}else if(pageNumbers.length===3){
tempPageNumbers=[1,2,3];
}else if(pageNumbers.length===4){
tempPageNumbers=[1,2,3,4];
}else if(pageNumbers.length===5){
tempPageNumbers=[1,2,3,4,5];
}else if(pageNumbers.length===6){
tempPageNumbers=[1,2,3,4,5,6];
}else if(pageNumbers.length>=7&&props.currentPage>=1&&props.currentPage<=4){
tempPageNumbers=[1,2,3,4,5,"...",pageNumbers.length];
}else if(props.currentPage>=5&&props.currentPage+4<=pageNumbers.length){
tempPageNumbers=["1...",props.currentPage-2,props.currentPage-1,props.currentPage,props.currentPage+1,props.currentPage+2,"...",pageNumbers.length];
}else{
tempPageNumbers=["1...",pageNumbers.length-4,pageNumbers.length-3,pageNumbers.length-2,pageNumbers.length-1,pageNumbers.length];
}
return(
<div className={"pagination-container"}>
<div className={"pages-container"}>
<div className={"each-page"} onClick={handlePrevOnClick}>
<div className={"page-number"}>
Prev
</div>
</div>
{tempPageNumbers.map((page)=>{
if(page==="1..."){
return(
<div className={"each-page"} onClick={()=>{props.setCurrentPage(1)}}>
<div className={"page-number"}>
{page}
</div>
</div>
)
}else if(page===props.currentPage){
return(
<div className={"current-page"} onClick={()=>{props.setCurrentPage(page as number)}}>
<div className={"current-page-number"}>
{page}
</div>
</div>
)
}else if(page==="..."){
return(
<div className={"dot-dot-page"}>
<div className={"page-number"}>
{page}
</div>
</div>
)
}
else{
return(
<div className={"each-page"} onClick={()=>{props.setCurrentPage(page as number)}}>
<div className={"page-number"}>
{page}
</div>
</div>
)
}
})}
<div className={"each-page"} onClick={handleNextOnClick}>
<div className={"page-number"}>
Next
</div>
</div>
</div>
</div>
)
}
I expect to see products get shown starting from the first page. I think the problem is mainly with wrong pagination. The pagination doesn't start with the first page.
I will appreciate anyone who can help me with this problem! I have been stuck for several days... Million thanks in advance!

React - Each child in a list should have a unique 'key' prop

As my first react project, I decided to try and make a Pokedex.
I have an array of Pokemon and that I pass into a List component and use the .map() function to render. I understand that the root-most element of that the .map() function returns needs a unique key and I understand that it is ideal if the key can be truly unique to the item so that if the list is sorted, items have the same key. Therefore, I figured using the 'id' of the pokemon would be ideal. I believe I have done that but I cannot get rid of the warning in console. I'd really appreciate a hand with this.
export default class List extends React.Component {
render() {
const { list, nav } = this.props;
return (
<div className="list">
{list.map((pokemon) => (
<PokemonItem key={pokemon.id} navigation={nav} pokemon={pokemon} />
))}
</div>
);
}
}
PokemonItem Render Method
render() {
const { pokemon, navigation } = this.props;
return (
<div onClick={() => {
navigation.navigate("Details", { pokemon });
}}
className={"list-item bg_" + pokemon.types[0]}>
<div className="header">
<div className="name">{pokemon.name}</div>
<div className="id">#{this.getId(pokemon.id)}</div>
</div>
<div className="body">
<div className="types">
{pokemon.types.map((type) => {
return <div className="type">{type}</div>;
})}
</div>
<div className="sprite">
<img src={pokemon.imgURL} alt={pokemon.name} title={pokemon.name}></img>
</div>
</div>
<div className="background-image">
<img src={PkBall} alt="" />
</div>
</div>
);
}
Warning message showing in console
Checking your PokemonItem it reveals that the reason may be laying in this piece of code:
{pokemon.types.map((type) => {
return <div className="type">{type}</div>;
})}
This is easily fixed by adding the key attribute:
{pokemon.types.map((type) => {
return <div className="type" key={type.id}>{type}</div>;
})}
You need to add a key in every item returned from a map in order to avoid this error. Also I advice you to add the console output related to your question in the body so it's easier to pinpoint the errors.
After the edit of the OP's question the warning occurs here:
<div className="types">
{pokemon.types.map((type) => {
return <div className="type">{type}</div>;
})}
</div>
The key-property is not set for div and should be done like in the first method. If type is unique you can use this as key.

localStorage after updated web site is reset

In my react app I have 12 buttons and an array which has a length of 12 that is filled with the plus character: .fill("+");.
I have function that after clicking on one of these buttons that changes the Array(i) to ("-");
I need to save this Array in localStorage, but for this I create:
localStorge = localStorage.spots(spots=is my varryable in code) = JSON.stringify(Array(12).fill("-"));
I tap on my button and may local storage changed ==cool = everything works
but after reload my web my Array in local storage =
JSON.stringify(Array(12).fill("-"));
it is logic because I write it in beginning of the code, but I don't need it. I need to create local storage (Array(12).fill("-")) change it after clicking on my buttons and after reload local storage stayed changed.
app.js
export default class Hall extends React.Component {
constructor(props) {
super(props);
this.state = {
spots:JSON.parse(localStorage.spots),
}
}
handlClick(i) {
const spots =this.state.spots.slice();
spots[i]="бронь";
localStorage.spots=JSON.stringify(spots);
const color = this.state.color.slice();
color[i]="danger";
this.setState({
spots:JSON.parse(localStorage.spots),
color: color,
});
}
renderSquare(i) {
return (
<Spot
onClick={()=> this.handlClick(i)}
value={this.state.spots[i]}
/>
);
}
render() {
return (
<div className="BySpot">
<div className="date"></div>
<div className="inSpot">
<div className="screen">screen</div>
<div className="exit">exit</div>
<div className="board-row1">
board-row1
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row2">
board-row2
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row3">
board-row3
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
<div className="board-row4">
board-row4
{this.renderSquare(9)}
{this.renderSquare(10)}
{this.renderSquare(11)}
</div>
</div>
</div>
);
}
}
index.js
function Main(props) {
localStorage.spots = JSON.stringify(Array(12).fill("своб"));
return (
<main className="main" >
<Nav />
<WrapMain />
</main>
)
};
ReactDOM.render(
<Main />,document.getElementById("root")
);
That is a wrong syntax, you can't add value in localStorage that way. Try this:
localStorage.setItem('spots', JSON.stringify(spots))
and then you can get from localStorage
const spots = localStorage.getItem('spots')
and parse the spots variable if you need.
Here you can read more in docs.
https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage

Reactjs: Replying comments not working in reactjs

Replying comments not working in reactjs.
Believe I have search through this venerable forum but most solution found could not resolve my issue.
This code works fine by displaying post and its corresponding comments from an array. Great Thanks to Stackoverflow Engineer Ryan for his help. Now I want to display each reply made on each comments as per code below
{props.comment.replys.map((reply, i) => (<div>{reply.reply}</div>))}
but it shows error
Cannot read property 'replys' of undefined
at Post
In angularjs I can just implement code below inside Post ng-repeat function.
<div class="post" ng-repeat='post in posts'>
<div>
{{ post.content }}
</div>
<!-- Comments -->
<div ng-repeat='comment in post.comments'>
<div class='comment'>{{ comment.comment }} <b>{{ comment.id }}</b></div>
<div ng-repeat='reply in comment.replys'>
<div>{{ reply.reply }}</div></div>
</div>
</div>
Here is the updated code in reactjs.
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
const Post = (props) => {
console.log(props.post);
console.log(props.comments);
return (<React.Fragment><li >
{props.post.id} - {props.post.content}
</li>
<div>
{props.post.comments.map((comment, i) => (<div>{comment.comment} --- {comment.id}</div>))}
{props.comment.replys && props.comment.replys.map((reply, i) => (<div>{reply.reply}</div>))}
</div>
</React.Fragment>
);
};
class Comment extends React.Component {
constructor(props) {
super(props);
this.state = {
rec: [
{"id":"1","content":"first post","comments":[{"comid":"1","comment":"first comment","replys":[{"reply":"first comment reply1"},{"reply":"first comment second reply"}] }]},
{"id":"2","content":"second post","comments":[{"comid":"2","comment":"second comment", "replys":[{"reply":"second comment reply1"}] }]}
],
};
}
render() {
return (
<div>
<h3>Records</h3>
<ul>
{this.state.rec.map((post, i) => (
<Post post={post} key={i}/>
))}
</ul>
</div>
);
}
}
const Post = (props) => {
return (<React.Fragment>
<li>
{props.post.id} - {props.post.content}
</li>
<div>
{props.post.comments.map((comment, i) => (
<div key={"comment_" + comment.id}>
<div>{comment.comment} --- {comment.id}</div>
{comment.replys && comment.replys.map((reply, i) => (<div>{reply.reply}</div>))}// Here
</div>
))}
</div>
</React.Fragment>
);
};
You can take replays data in this way.
One comment on your second post in the sample data has no replies (replys) so it's quite expected that you see that error: you call map on undefined.
Try this instead (check if we have replies first and only map if some exist):
{props.comment.replys && props.comment.replys.map((reply, i) => (<div>{reply.reply}</div>))}
Edit
Here's one implementation of the Post method (I renamed it to renderPosts, you should do the same) that should work (better):
const renderPosts = (props) => {
return (
<>
<li>
{props.post.id} - {props.post.content}
</li>
<div>
{props.post.comments.map((comment) => {
return (
<div key={comment.comid}>
<div>{comment.comment} --- {comment.id}</div>
{comment.replys && comment.replys.map((reply) => <div key={reply.reply}>{reply.reply}</div>)}
</div>
)
})}
</div>
</>
);
};
Note that I've:
- replaced the outer element with the shorter notation for fragments
- moved the iteration of the replies inside of the iteration of the comments (each comment has a list of replies)
- added the mandatory key attribute (you should add an id to the replies on your datamodel, I used the reply.reply value for the moment but that's in general a bad id, because there's no guarantee that all replies are different)
Hope it helps!

My Toaster component is not creating multiple toasters on multiple clicks. Reactjs

I have made a toaster component which is only rendering 1 toaster on 1 or multiple clicks, but I need a component the renders multiple toasters on multiple clicks.
This is my Toaster Component.
import React, {Component} from 'react'
import '../stylesheets/adminlte.css'
ToastMsg = (props) => (
<div className=" snackbar" key={props.idx}>
<div className="card-header">
<h3 className="card-title">Toast</h3>
</div>
<div className="card-body">{props.message}</div>
<div className="card-footer"/>
</div>
)
createtoaster = () => {
if (this.state.show) {
return this
.state
.message
.map((msg, idx) => <ToastMsg idx={idx} message={msg}/>)
} else {
return null;
}
}
render() {
return (
<div className="col-md-2 offset-md-9">
<button className="btn btn-primary" onClick={this.handleOpen}></button>
{this.createtoaster()}
</div>
)
}
I am providing this.state.message from another component and passsing it via props. I cannot use any Library as per the requirement so if anyone can help me with this, It is appreciated. Also feel free to point out any mistakes in my code.
missing array element 'picker': < div className="card-body">{this.state.message [i] }
I would use map, too ... with key property for each item.
Are you sure you're receiving array with more elements ?

Resources