How to increase a usestate number inside a div in React.js - javascript

I have a useState inside div, I want to update the counter beacuse I want to get another img url from exArr array. is there a way to update counter inside a div?
let exArr = [];
const [counter, setCounter] = useState(0);
return (
<div className="menRight">
{
products.filter(product => product.productGender.includes('Kids')).slice(0, showProducts).map(product => (
<div className="menRightCard">
<Link to={`/productBuy?id=${product.productImageFolder}`}>
<div className="menRightCardimg">
<i className="far fa-heart"></i>
<img src={exArr[counter]} alt="" />
/* I WANT TO CHANGE HERE */ { setCounter(counter => counter + 1) }
</div>
<div className="menRightCardInfo">
<p className="productInfo">
{product.productName}
</p>
<p className="productPrice">
€{product.productPrice}
</p>
</div>
</Link>
</div>
))
}
<div className="loadMore">
<button onClick={showMoreItems}>Load More Products</button>
</div>
</div>
);
}

Related

react <i> tag onClick triggers only after double Click

I intend to use the "CopyToClipboard" package so that when you click on the tag below, something is saved to the clipboard. This also works currently, but only if you double click on the tag. How do I solve it that I only have to click once and it appears directly on the clipboard?
const Card = (props: ICardProps) => {
// // State of Clipboard
const [clipboard, setClipboard] = useState("");
const [copied, setCopied] = useState(false);
const cpyClip = () => {
setClipboard(`short.url/${props.shortUrl.shortUrl}`);
setCopied(false);
};
return (
<div>
<div className="card-body">
<div className="card-section">
<div className="icon-controller">
<CopyToClipboard
text={clipboard}
onCopy={() => {
setCopied(true);
}}
>
<span></span>
</CopyToClipboard>
<CopyToClipboard text={clipboard} onCopy={() => setCopied(copied)}>
<i onClick={cpyClip} className="far fa-copy"></i>
</CopyToClipboard>
</div>
</div>
</div>
</div>
);
};
Because you're only setting clipboard, the string to copy, when someone clicks on the <i>.
Try something like
const Card = (props: ICardProps) => {
const url = `short.url/${props.shortUrl.shortUrl}`;
const [copied, setCopied] = useState(false);
return (
<div className="card-body">
<div className="card-section">
<div className="icon-controller">
<CopyToClipboard text={url} onCopy={() => setCopied(true)}>
<i className="far fa-copy" />{copied ? 'Copied' : null}
</CopyToClipboard>
</div>
</div>
</div>
);
};
instead.

How can I delete an item from my todolist

I am trying to learn react js , but I don't know how to delete an item from my list, could you help me ? Actually, I am not professional , but I am really interested in learning, there is my codes which add some new item to my list properly, but I don't know how to delete them when I click on their checkbox/delete button.
import React, { useState } from "react";
const App = () => {
const [NewTaskText, setNewTaskText] = useState("");
const [Tasks, setTasks] = useState(["do a task", "samira"]);
const addTask = (e) => {
e.preventDefault();
if (!NewTaskText) return;
setTasks((currentTasks) => {
return [...currentTasks, NewTaskText];
});
setNewTaskText("");
};
const onchangeInput = (e) => {
const value = e.target.value;
setNewTaskText(value);
};
return (
<div className="row">
<form onSubmit={addTask}>
<div className="row col s6">
<div className="input-field col s10">
<textarea
id="textarea1"
className="materialize-textarea"
value={NewTaskText}
onChange={onchangeInput}
></textarea>
<label htmlFor="textarea1">What needs to be done ?</label>
</div>
</div>
<div className="row col s6">
<br></br>
<a className='waves-effect waves-light btn' href="/#" onClick={addTask}>
<i className='material-icons left' >
add_circle
</i>
Add
</a>
</div>
</form>
<div className="row">
<div className="row col s9">
<ul className="collection with-header">
<li className="collection-header">
<h4>Todo List</h4>
<form>
<div className="input-field">
<input id="search" type="search" required />
<label className="label-icon" htmlFor="search">
<i className="material-icons">search</i>Search
</label>
<i className="material-icons">close</i>
</div>
</form>
</li>
<label>
{Tasks.map((item, i) => {
return (
<li className="collection-item" key={i}>
<input type="checkbox" />
<span>
{item}
</span>
<span>
<a href="#!" className="secondary-content">
<i className="material-icons" >delete</i>
<i className="material-icons">check_circle</i>
</a>
</span>
</li>
);
})}
</label>
</ul>
</div>
</div>
</div>
);
};
export default App;
You can delete the item from the array by using index:
<i className="material-icons" onClick={() => handleDelete(i)}>delete</i>
and define your function above the return statement:
const handleDelete = i => {
const taskList = [...Tasks]
taskList.splice(i, 1)
setTasks(taskList)
}
Here it is important to know that you have to make a copy of the state if it is an object or an array. Because if you modify the original array or object, react won't register that as a change, and won't re-render. That is why I did const taskList = [...Tasks]. You can also use a library like lodash which provides some neat ways of handling objects and arrays
Just add a onClick handler to button which should delete item
<i className="material-icons" onClick={ () => {
setTasks((prevTasks) => {
const updatedPrevTasks = [...prevTasks];
updatedPrevTasks.splice(i, 1);
return updatedPrevTasks;
});
}}>delete</i>

OnClick() handler in map function is changing the state of all elements instead of only clicked element

I am creating a Next js site mcqs and answer.
Initially only questions are rendered with the title and options.
There is a button to show the answer of given question but when button is clicked it is changing the state of all elements in the map function instead of element that is clicked.
export default function Chapter({ chapter }) {
const [right, setRight] = useState(false)
function handleOnClick() {
setRight(!right)
}
<main className='main_q'>
<h1>{chapter.items[0].name}</h1>
{chapter.items[0].questions.items.map((question, index) => {
return (
<div key={question.id} className='question_container'>
<div className='question_q_t'>
<div className='question_q'>Q</div>
<div className='question_t'>
<Markdown>{question.title}</Markdown>
</div>
</div>
<div className='option_container'>
<div className='option_a_o'>
<div className='option_a'>A</div>
<div className='option_o'>
<Markdown>{question.optionA}</Markdown>
</div>
</div>
<div className='option_a_o'>
<div className='option_a'>B</div>
<div className='option_o'>
<Markdown>{question.optionB}</Markdown>
</div>
</div>
<div className='option_a_o'>
<div className='option_a'>C</div>
<div className='option_o'>
<Markdown>{question.optionC}</Markdown>
</div>
</div>
<div className='option_a_o'>
<div className='option_a'>D</div>
<div className='option_o'>
<Markdown>{question.optionD}</Markdown>
</div>
</div>
</div>
<a
className='solution_link'
target='_blank'
href={`/${question.chapter.subject.category.slug}/${question.chapter.subject.slug}/${question.chapter.slug}/${question.id}`}
>
See Solution
</a>
<button onClick={handleOnClick}>Answer</button>
{right && <div>{question.rightAnswer}</div>}
</div>
)
})}
</main>
}
Put each question div into its own component, and make a right state in that component:
const Question = ({ question }) => {
const [right, setRight] = useState(false)
return (
<div key={question.id} className='question_container'>
// etc
Or make an array of right states in the parent:
export default function Chapter({ chapter }) {
const qs = chapter.items[0].questions.items;
const [rights, setRights] = useState(qs.map(q => false));
const makeHandleClick = (i) => {
setRights(
rights.map((r, j) => j === i ? r : !r)
);
};
// ...
<button onClick={makeHandleClick(i)}>Answer</button>
{rights[i] && <div>{question.rightAnswer}</div>}

React/Redux, Redux store changes but does not immediately render items without leaving the page and returning

When I clicked on the button "Buy", the store redux is updated and
push a new array to the initial state. But I don't see any new render
in the shop-cart section without leaving the page and go in again so I
can see new items. I'm new to React and Redux, I have been trying to fix it but it was not working and i'm very confused about it
Here is the reducer section
const initialState = {
counter : 0,
cartData : [
{
id : 1,
name : "Melon",
price : 100,
img : "https://d1hr6nb56yyl1.cloudfront.net/product-images/93368-280.jpg",
quantity : 1
},
{
id : 1,
name : "Melon",
price : 100,
img : "https://d1hr6nb56yyl1.cloudfront.net/product-images/93368-280.jpg",
quantity : 1
},
]
};
function cartNumber(state = initialState, action) {
console.log(state.cartData)
let cartIndex = [...state.cartData];
switch(action.type){
case "INCREMENT" :
return {
...state,
cartData : cartIndex.concat(action.newData)
};
break;
case "DECREMENT" :
default :
return state;
}
return cartIndex
}
export default cartNumber;
Here is the Item Detail page and Items Cart section
import React, {useEffect,useState} from "react";
import SubCart from "../components/SubCart";
import { useSelector, useDispatch } from "react-redux";
import {Link} from "react-router-dom";
function ItemDetail({match, history}){
const dispatch = useDispatch();
const [item, setItem] = useState({});
const scroll = () => {window.scroll(0,0)};
useEffect(() => {
const fetchItem = async () => {
const fetchItem = await fetch(
`https://5e5a9fc26a71ea0014e61f04.mockapi.io/api/${match.params.category}/${match.params.id}`
);
const item = await fetchItem.json();
setItem(item);
};
fetchItem();
scroll();
}, [])
const showRating = (rating) => {
var result = [];
for(var i = 1; i <= rating; i++){
result.push(<i className="fa fa-star" key={i + 1} style={{fontSize : ".8rem", color : "#ff4e00", padding : "0rem .1rem"}}></i>);
}
for (var j = 1; j <= (5-rating); j++) {
result.push(<i className="far fa-star" key={i + 1} style={{fontSize : ".8rem", padding : "0rem .1rem"}}></i>);
}
return result;
}
const backButton = () => {
history.goBack();
}
const showSubcart = () => {
let sub = document.getElementById("subcart-section");
let bg = document.getElementById("bg-ccc");
sub.classList.toggle("showSubCart");
bg.classList.toggle("bg-ccc");
dispatch({type : "INCREMENT", newData : item });
}
return (
<div style={{backgroundColor: "white"}}>
<div className="item-detail" style={{paddingBottom : "1rem"}}>
<div className="section-heading">
<div className="section-content">
<div className="icon-home">
<i className="fas fa-home"></i>
</div>
<div className="nav-home">
<Link to="/">Home</Link>
</div>
<div className="icon-to">
<i className="fas fa-chevron-right"></i>
</div>
<div className="nav-cart">
<Link to="/">{item.category}</Link>
</div>
</div>
</div>
<div className="img-detail">
<img src={item.img} alt={item.name} />
<span className="icon-section"><i className="far fa-heart"></i></span>
<span className="icon-section-arrow" onClick={() => backButton()}><i className="fas fa-arrow-left"></i></span>
</div>
<div className="item-detail-content">
<div className="container">
<Link to="/" style={{color : "black"}}><span className="category">{item.category}</span></Link>
<div><h2>{item.name}</h2></div>
<div><h3>{item.price}$</h3></div>
<div>
<ul>
<li>{showRating(item.rating)} <span style={{fontSize : ".8rem"}}>(210)</span></li>
</ul>
</div>
<div className="buy" onClick={() => showSubcart()}>
<span className="buy-text">Buy</span>
<span className="buy-icon"><i className="fas fa-shopping-cart"></i></span>
</div>
<div className="description">
<div className="head-description">
<h3><i className="far fa-bookmark"></i> Description</h3>
</div>
<div className="body-description">
<p>...</p>
</div>
</div>
<div className="infoPolicy mt-top">
<div className="box-head">
<i className="fas fa-truck"></i>
</div>
<div className="box-content">
<p className="note-p">FREE NATIONAL DELIVERY</p><span className="note">(Products over 50$)</span>
</div>
</div>
<div className="infoPolicy mt-top">
<div className="box-head">
<i className="fas fa-sync-alt"></i>
</div>
<div className="box-content">
<p className="note-p">Returns are Easy</p><span className="note">(Return 30days for items)</span>
</div>
</div>
<div className="infoPolicy mt-top mt-bt">
<div className="box-head">
<i className="fas fa-headset"></i>
</div>
<div className="box-content">
<p className="note-p">Telephone consultation</p><span className="note">(Free from 8:00 - 21:00 every day)</span>
</div>
</div>
</div>
</div>
<SubCart />
</div>
</div>
);
}
export default ItemDetail;
import React, {useState} from "react";
import {Link} from "react-router-dom";
import {useSelector} from "react-redux";
function ItemCart(){
let data = useSelector(state => state.cartData);
let [items, setItem] = useState(data);
return (
<div className="subcart-link">
{items.map((item, index) => (
<div className="d-flex" key={index}>
<div className="subcart-img">
<img src={item.img} alt="pubg"/>
</div>
<div className="subcart-item-content">
<Link to="/">{item.name}</Link>
<div className="subcart-item-detail">
<p>{item.price}$<span className="subcart-quantity">x 2</span></p>
</div>
</div>
<div className="delete-click">
<p>x</p>
</div>
</div>
))}
</div>
);
}
at your ItemCart you are duplicating redux state into a react state, which is not advisable. they are two different entities, though you can have both types at your application a given specific state should be handled by a specific state manager.
at your ItemCart remove useState altogether, and map over data variable instead. your issue comes from the fact that your items state inherits only the original redux state, but since they are different states, it doesnt get updated when redux state changes.
fwiw, dont use dom manipulation to handle classes like you do at showSubCart, this is not good. I suggest to use some boolean logic instead to toggle class, based on some props or state value.

React Error: Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null

EDIT: [SOLVED by the community - in the answers!] Thanks everyone
I'm trying to add search functionalities to my webApp (a list of the movies I own). To do this, from the app I'm calling a functional component (MovieListFiltered) which has the following code:
MovieListFiltered.js:
import React from 'react'
const MovieListFiltered = (props) => {
const newData = props.moviesAfterFilter
if(newData !== null) {
const newMovies = newData.map((movie, i) =>
{
return(
<div className="col s12 m3 l3" key={i} movieid ={movie.idFromTmdb}>
<div className="card">
<div className="card-image waves-effect waves-block waves-light">
<img src={movie.url2poster} alt={movie.movieTitle} className="responsive-img" />
<p className="littleFont" align="center"><span><b>{movie.movieTitle}</b></span></p>
</div>
<div className="card-action">
<a href="#" onClick={() => this.props.viewMovieInfo(movie.idFromTmdb)}>Movie Details</a>
</div>
</div>
</div>
);
})
console.log(newMovies)
props.movieCallback(newData, newMovies);
} else {
return null
}
}
export default MovieListFiltered
So, basically, notything special there: you see many console.log calls, that was just to make sure the correct array of data was passed (and it is!)
In App.js:
... code not interesting goes here ...
callbackFromList = (childDataData, childDataMovies) => {
this.setState({moviesToFilter: childDataData});
this.setState({moviesToShow: childDataMovies});
this.setState({totalResults: childDataData.length});
}
render()
{
... some not interesting code goes here...
return(
<div className="App">
<Nav />
<div>
<div className="container">
<div className="row">
<div className="col s10 offset-s1">
<MovieListFiltered viewMovieInfo={this.viewMovieInfo} movieCallback={() => this.callbackFromList} ref={this.movieListRef} moviesAfterFilter={this.state.moviesFiltered}></MovieListFiltered>
</div>
</div>
</div>
</div>
</div>
);
}
Can you please help me? I've read all the questions already made here on stackoverflow, but nothing seems to fit to my case.
I think you are wanting something like this:
const MovieListFiltered = (props) => {
const newData = props.moviesAfterFilter
if(newData !== null) {
const newMovies = newData.map((movie, i) => (
<div className="col s12 m3 l3" key={i} movieid ={movie.idFromTmdb}>
<div className="card">
<div className="card-image waves-effect waves-block waves-light">
<img src={movie.url2poster} alt={movie.movieTitle}
className="responsive-img" />
<p className="littleFont" align="center"><span><b>
{movie.movieTitle}</b></span></p>
</div>
<div className="card-action">
<a href="#" onClick={() =>
this.props.viewMovieInfo(movie.idFromTmdb)}>Movie Details</a>
</div>
</div>
</div>
);
)
console.log(newMovies)
props.movieCallback(newData, newMovies)
return newMovies
} else {
return null
}
}
Here a cleaner version with only one return. That may not be what you're looking for though.
import React from 'react'
const MovieListFiltered = (props) => {
const newData = props.moviesAfterFilter || []; // add 'or' if null or undefined
const newMovies = newData.map((movie, i) => (
<div className="col s12 m3 l3" key={i} movieid ={movie.idFromTmdb}>
<div className="card">
<div className="card-image waves-effect waves-block waves-light">
<img src={movie.url2poster} alt={movie.movieTitle} className="responsive-img" />
<p className="littleFont" align="center"><span><b>{movie.movieTitle}</b></span></p>
</div>
<div className="card-action">
<a href="#" onClick={() => this.props.viewMovieInfo(movie.idFromTmdb)}>Movie Details</a>
</div>
</div>
</div>
));
console.log(newMovies)
props.movieCallback(newData, newMovies);
return newMovies;
}
export default MovieListFiltered
You are only returning a value from the else block. The if block is not currently returning anything. You probably want to make the last line of the if block return newMovies;
import React from 'react'
const MovieListFiltered = (props) => {
const newData = props.moviesAfterFilter
if(newData !== null) {
const newMovies = newData.map((movie, i) =>
{
return(
<div className="col s12 m3 l3" key={i} movieid ={movie.idFromTmdb}>
<div className="card">
<div className="card-image waves-effect waves-block waves-light">
<img src={movie.url2poster} alt={movie.movieTitle} className="responsive-img" />
<p className="littleFont" align="center"><span><b>{movie.movieTitle}</b></span></p>
</div>
<div className="card-action">
<a href="#" onClick={() => this.props.viewMovieInfo(movie.idFromTmdb)}>Movie Details</a>
</div>
</div>
</div>
);
});
console.log(newMovies);
props.movieCallback(newData, newMovies);
return newMovies;
}
return null;
}
export default MovieListFiltered
Also, you might notice I got rid of the entire else block - this is because it's not necessary if you return from the corresponding if block.

Categories