I wrote down the code below.
My outcome should be 4 buttons that increment and decrement a value.
Is working but all buttons change at the same time!
The outcome I would like to get button by button and not at the same time.
I've already tried with an Array but seems I'm not on the right way!
import React from 'react';
class Counter extends React.Component {
constructor() {
super();
this.state = {
cnt: 0
};
}
handleDecrement = () => {
this.setState({
cnt: this.state.cnt + 1
});
}
handleIncrement = () => {
this.setState({
cnt: this.state.cnt - 1
});
}
render() {
return (
<><div className = "btn"></div>
<header>
<h1>Tarantino Shop</h1>
</header>
<div>
<img src= "images/walltara.png" alt="cart" width = "80%"/>
</div>
<div className="divprimario">
<div className="items">
<img src= "images/tara1.jpg" alt="cart" />
<div className = "titles"> T-Shirt Pulp Fiction</div>
<div>
<button onClick={this.handleDecrement}>+</button>
<p>{this.state.cnt} </p>
<button onClick={this.handleIncrement}>-</button>
</div>
</div>
<div className="items">
<img src= "images/tara2.jpg" alt="cart" />
<div className = "titles">T-Shirt Tarantino </div>
<div>
<button onClick={this.handleDecrement}>+</button>
<p>{this.state.cnt} </p>
<button onClick={this.handleIncrement}>-</button>
</div>
</div>
<div className="items">
<img src= "images/tara3.jpg" alt="cart" />
<div className = "titles">T-Shirt Le Iene</div>
<div>
<button onClick={this.handleDecrement}>+</button>
<p>{this.state.cnt} </p>
<button onClick={this.handleIncrement}>-</button>
</div>
</div>
<div className="items">
<img src= "images/tara4.jpg" alt="cart" />
<div className = "titles">T-Shirt Random</div>
<div>
<button onClick={this.handleDecrement}>+</button>
<p>{this.state.cnt} </p>
<button onClick={this.handleIncrement}>-</button>
</div>
</div>
</div>
</>
);
}
}
export default Counter;
So, why all the buttons change at the same time? What am I'm doing wrong?
you are only using one variable cnt to keep track of the count. If you want them to update separately, each button must increment or decrement a different state variable.
For example you could use pulpFictionCnt, tarantinoCnt etc to keep track of the different counts.
Keep a separate component for your Counter and provide other data as props.
import React from "react";
class Counter extends React.Component {
constructor() {
super();
this.state = {
cnt: 0
};
}
handleDecrement = () => {
this.setState({
cnt: this.state.cnt + 1
});
};
handleIncrement = () => {
this.setState({
cnt: this.state.cnt - 1
});
};
render() {
return (
<>
<div className="divprimario">
<div className="items">
<img src="images/tara1.jpg" alt="cart" />
<div className="titles">{this.props.title}</div>
<div>
<button onClick={this.handleDecrement}>+</button>
<p>{this.state.cnt} </p>
<button onClick={this.handleIncrement}>-</button>
</div>
</div>
</div>
</>
);
}
}
export default Counter;
Following may be some other component,
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import Counter from "./Counter";
const rootElement = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<div>
<div className="btn"></div>
<header>
<h1>Tarantino Shop</h1>
</header>
<div>
<img src="images/walltara.png" alt="cart" width="80%" />
</div>
<Counter title={"T-Shirt Pulp Fiction"} />
<Counter title={"T-Shirt Tarantino"} />
<Counter title={"T-Shirt Le Iene"} />
<Counter title={"T-Shirt Random"} />
</div>
</StrictMode>,
rootElement
);
Sandbox code here => https://codesandbox.io/s/laughing-bhabha-zsyvw?file=/src/Counter.js
Related
I am building a small Countries App in React. The issue I have is that I have changed the endpoint and now it is not returning anything. I checked this in Sandbox and it worked fine. Below is the code for the page that renders the details of the country.
import React from 'react';
import { useEffect } from "react";
import { useState } from "react";
import { NavBarCard } from '../NavBar/NavBarCard';
import './DetailCountryCard.css';
import {Link} from 'react-router-dom';
function DetailCountryCard ({ match }) {
useEffect(() => {
fetchItem();
console.log(match);
// eslint-disable-next-line
}, []);
const [country, setCountry] = useState({});
const [darkMode, setDarkMode] = useState(false);
const fetchItem = async () => {
const fetchItem = await fetch(
`https://restcountries.eu/rest/v2/alpha/${match.params.alpha3Code}`
);
const country = await fetchItem.json();
setCountry(country);
console.log(country);
};
return (
// <div>
// <h1>the country</h1>
// </div>
<div className={darkMode ? "dark-mode" : "light-mode" }>
<NavBarCard handlechange={()=> setDarkMode(prevMode => !prevMode)} moonMode={darkMode ? "moon fas fa-moon" :
"moon far fa-moon"}
darkMode={darkMode ? "dark-mode" : "light-mode"}/>
<div className="detailCard">
<Link to="/">
<button className="topButton myButton">Back</button>
</Link>
<div className="container">
<img className="flag" alt="flag" src={country.flag} />
<div className="countryName">
<div className="NativeName">
<h1 className="Country">{country.name}</h1>
<h2>Native Name:</h2>
<p> {country.nativeName}</p>
<br />
<h2>Population:</h2>
<p> {country.population}</p>
<br />
<h2>Region:</h2>
<p> {country.region}</p>
<br />
<h2>Sub Region:</h2>
<p> {country.subregion}</p>
<br />
<h2>Capital:</h2>
<p> {country.capital}</p>
<br />
<div>
<h2>Border Countries:</h2>{country.borders && country.borders.map(function(border){
return(
<Link to={`/DetailCard/${border}`}>
<button className="myButton"> {border} </button>
</Link>
)
})}
</div>
</div>
</div>
<div className="domain">
<h2>Top Level Domain: </h2>
<p>{country.topLevelDomain}</p>
<br />
<h2>Currencies: </h2>
<p>{country.currencies && country.currencies.map(({ name }) => name).join(", ")}</p>
<br />
<h2>Languages: </h2>
<p>{country.languages && country.languages.map(({ name }) => name).join(", ")}</p>
<br />
</div>
</div>
</div>
</div>
);
}
export default DetailCountryCard;
All I get is blank page and in the console it saying that I am getting a status of 400. Any help would be appreciated. If I just put bra as the last three letters of the alpha code this is what I get.
I am using the Context API to manage state in a small app. I get the response OK, the Consumer has it, so I map through it and want to pass down data from it to a Product Card component through props. And the Product Card renders absolutely nothing. I get no errors whatsoever. Can anyone help me out please? Here is the code of parent component:
import Pagination from "./Pagination";
import { Consumer } from "../context";
export default class Browse extends Component {
render() {
return (
<Consumer>
{value => {
const { search } = value;
return (
<ProductsGrid>
{search.map(beer => (
<ProductCard
key={beer.id}
beerId={beer.id}
beerName={beer.name}
beerTagline={beer.tagline}
beerAbv={beer.abv}
firstBrewed={beer.first_brewed}
imageUrl={beer.image_url}
/>
))}
</ProductsGrid>
);
}}
</Consumer>
);
}
}`````
and here is the Product Card component:
```export default class ProductCard extends React.Component {
render() {
return (
<div className="product-card">
<div className="product-card-inner">
<div className="product-info-container">
<h1 className="beer-name">{this.props.beerName}</h1>
<p className="beer-type">{this.props.beerTagline}</p>
<p className="beer-alcohol">{this.props.beerAbv}%</p>
<p className="first-brewed">
First brewed: {this.props.firstBrewed}
</p>
</div>
<div className="beer-image-container">
<img src={this.props.imageUrl} alt="beer" />
</div>
<div className="price-container">
<h1>£ 3.50</h1>
</div>
<div className="button-container">
<div className="quantity-container">
<p className="minus-sign"> - </p>
<p className="qty-number"> 0 </p>
<p className="plus-sign"> + </p>
</div>
<div className="add-container">
<IoIosCart />
<p>Add</p>
</div>
</div>
</div>
</div>
);
}
}```
I'm building a NetFlix clone main page.
I have already the list of movies,tv series ecc.. rendered horizontal.
I'd like to click on the next arrow and slide only the relative section.
Now if I click the next arrow on the first section, the second one above scroll and I don't want that..
How can I achieve it?
I tried to google it and some tutorials but I can't find how to target elements in the same parent with onClick.
Thank you very much
class App extends React.Component {
state = { moviesNow: [], tvSeries: [], actionMovies: [], animation: [] };
containerSection = React.createRef();
handleClick = e => {
this.containerSection.current.style.transform = `translateX(-100%)`;
};
render() {
return (
<div className="container">
<h1 className="section-title">Now playing</h1>
<div className="wrapper">
<div className="nextArrow" onClick={this.handleClick}>
<img src={nextArrow} alt="" />
</div>
<div ref={this.containerSection} className="container-section">
<MovieItem movies={this.state.moviesNow} />
</div>
</div>
<h1 className="section-title">TV Series</h1>
<div className="wrapper">
<div className="nextArrow" onClick={this.handleClick}>
<img src={nextArrow} alt="" />
</div>
<div ref={this.containerSection} className="container-section">
<MovieItem movies={this.state.tvSeries} />
</div>
</div>
You are using only one ref for two different elements, I guess that is where you issue is coming from. So I updated handleClick to be able to receive a ref as an argument and return a function that will receive the event :
handleClick = ref => e => {
ref.current.style.transform = `translateX(-100%)`;
};
Then you can use handleClick this way:
<div className="nextArrow" onClick={this.handleClick(secondContainerSection)}>
<img src={nextArrow} alt="" />
</div>
Eventually it gives you something like this:
class App extends React.Component {
state = { moviesNow: [], tvSeries: [], actionMovies: [], animation: [] };
containerSection = React.createRef();
//a new ref
secondContainerSection = React.createRef();
handleClick = ref => e => {
ref.current.style.transform = `translateX(-100%)`;
};
render() {
return (
<div className="container">
<h1 className="section-title">Now playing</h1>
<div className="wrapper">
<div className="nextArrow" onClick={this.handleClick(containerSection)}>
<img src={nextArrow} alt="" />
</div>
<div ref={this.containerSection} className="container-section">
<MovieItem movies={this.state.moviesNow} />
</div>
</div>
<h1 className="section-title">TV Series</h1>
<div className="wrapper">
<div className="nextArrow" onClick={this.handleClick(secondContainerSection)}>
<img src={nextArrow} alt="" />
</div>
<div ref={this.secondContainerSection} className="container-section">
<MovieItem movies={this.state.tvSeries} />
</div>
</div>
make a seperate component for drawer and define the ref inside it
drawer Component
class Drawer extends React.Component {
containerSection =new React.createRef();
handleClick = e => {
this.containerSection.current.style.transform = `translateX(-100%)`;
};
render() {
return (
<div className="wrapper">
<div className="nextArrow" onClick={this.handleClick}>
<img src={nextArrow} alt="" />
</div>
<div ref={this.containerSection} className="container-section">
{this.props.children}
</div>
</div>
Main component
class App extends React.Component {
state = { moviesNow: [], tvSeries: [], actionMovies: [], animation: [] };
containerSection = React.createRef();
handleClick = e => {
this.containerSection.current.style.transform = `translateX(-100%)`;
};
render() {
return (
<div className="container">
<h1 className="section-title">Now playing</h1>
<Drawer><MovieItem movies={this.state.moviesNow} /></Drawer>
<h1 className="section-title">TV Series</h1>
<Drawer><MovieItem movies={this.state.tvSeries} /></Drawer>
</div>);
I am new at React. Will be glad if someone can help:
I have parent (Dashboard) which contains all data. This data is passed to the children component (OnBoardingCard).
How can I render n times the OnBoardingCard component based on the data in the object at Dashboard without using the [num](in this case 3 times - 3x OnBoarding Cards;)?
Thank you!!
Parent- Dashboard
const cardData = [
{
svg: icon1,
title: 'Add',
content: 'add more'},
{
svg: icon2,
title: 'remove',
content: 'remove'
},
{
svg: icon3,
title: 'move',
content: 'move down'
}];
class Dashboard extends Component {
render() {
return (
<Section>
<OnboardingCard listData={cardData}/>
</Section>
);
} }
Children- OnBoardingCard
import Dashboard from "../../../../screens/Dashboard/index.js";
class OnboardingCard extends Component {
render() {
return (
<div className={styles.cardHolder}>
<div className={styles.fullCard}>
<div className={styles.onboardingCard}>
<div className={styles.iconBackground}>
<img src={this.props.listData[0].svg} />
</div>
<div className={styles.title}>{this.props.listData[0].title}</div>
</div>
<p className={styles.cardDescription}>
{this.props.listData[0].content}
</p>
</div>
</div>
); }}
When you are using a map inside render assign a unique key to its child component.
render(){
return(
{this.props.listData.map((item, i) =>
<div className={styles.cardHolder} key={i}>
<div className={styles.fullCard}>
<div className={styles.onboardingCard}>
<div className={styles.iconBackground}>
<img src={this.props.listData[0].svg} />
</div>
<div className={styles.title}>{this.props.listData[0].title}</div>
</div>
<p className={styles.cardDescription}>
{this.props.listData[0].content}
</p>
</div>
</div>
)}
);
}
You can use map function,
like this,
{this.props.listData.map((item)=>
<div className={styles.cardHolder}>
<div className={styles.fullCard}>
<div className={styles.onboardingCard}>
<div className={styles.iconBackground}>
<img src={item.svg} />
</div>
<div className={styles.title}>{item.title}</div>
</div>
<p className={styles.cardDescription}>
{item.content}
</p>
</div>
</div>)}
<Section>
<div className={styles.cardRow}>
{cardData.map((card, i) => (
<OnboardingCard {...card} key={i} />
))}
</div>
</Section>
This is what I meant (and wanted to do). So this solves my question. Thanks everyone!!
I want to use the same function showHide to show/hide each element within the parent.
When I press the button all 3 blocks reacts and hide or show.
How can I extend the function to work individualy for each div?
This is a localhost test project so I can't provide any link unfortunately.
Here you can see the final result
import React, { Component } from 'react';
class Homepage extends Component {
constructor( props ){
super( props )
this.state = {show : true};
this.showHide = this.showHide.bind(this)
}
render() {
return (
<section id="content">
<div className="top-content">
<div className="container">
<h1>React</h1>
<h2>A JavaScript library for building user interfaces</h2>
</div>
</div>
<div className="container">
<div>
<div>
<h3>Declarative</h3>
<button onClick={this.showHide} className="button-primary btn">{this.changeName()}</button>
{ this.state.show &&
<div>
<p>text</p>
<p>text</p>
</div>
}
</div>
<div>
<h3>Component-Based</h3>
<button onClick={this.showHide} className="button-primary btn">{this.changeName()}</button>
{ this.state.show &&
<div>
<p>text</p>
<p>text</p>
</div>
}
</div>
<div>
<h3>Learn Once, Write Anywhere</h3>
<button onClick={this.showHide} className="button-primary btn">{this.changeName()}</button>
{ this.state.show &&
<div>
<p>text</p>
<p>text</p>
</div>
}
</div>
</div>
</div>
</section>
);
}
changeName(){
let text = "text "
text += this.state.show === true ? "hide" : "show";
return text;
}
showHide(){
const { show } = this.state;
this.setState( { show : !show})
}
}
export default Homepage;
The problem here is that your using the same state variable for each div (this.state.show).
If you want to have the divs behave differently, they each need their own state.
import React, { Component } from 'react';
class Homepage extends Component {
constructor( props ){
super( props )
this.state = {show: [true, true,true]};
}
render() {
return (
<section id="content">
<div className="top-content">
<div className="container">
<h1>React</h1>
<h2>A JavaScript library for building user interfaces</h2>
</div>
</div>
<div className="container">
<div>
<div>
<h3>Declarative</h3>
<button onClick={()->this.showHide(0)} className="button-primary btn">{this.changeName()}</button>
{ this.state.show[0] &&
<div>
<p>text</p>
<p>text</p>
</div>
}
</div>
<div>
<h3>Component-Based</h3>
<button onClick={()->this.showHide(1)} className="button-primary btn">{this.changeName()}</button>
{ this.state.show[1] &&
<div>
<p>text</p>
<p>text</p>
</div>
}
</div>
<div>
<h3>Learn Once, Write Anywhere</h3>
<button onClick={()->this.showHide(2)} className="button-primary btn">{this.changeName()}</button>
{ this.state.show[2] &&
<div>
<p>text</p>
<p>text</p>
</div>
}
</div>
</div>
</div>
</section>
);
}
changeName(){
let text = "text "
text += this.state.show === true ? "hide" : "show";
return text;
}
showHide(num){
this.setState((prevState) => {
const newItems = [...prevState.show];
newItems[num] = !newItems[num];
return {show: newItems};
});
}
}
export default Homepage;
Obviously there are nicer ways of doing this, but this is just an example to show the separation of states.
Can't test it right now, but shouldn't be far off.
UPDATE: #Lasitha ty for the much nicer edit!