How to perform the mutation of dropdowns status in ReactJS? - reactjs

I want to make a change of state when an item is selected in my dropdown but a bug occurs that does not change without clicking again.
I know there are related questions but my code is a particular case.
The same thing happens to me as this image with my two dropdown.
I change "Mes" but it does not work until you return and select another value. There I just changed to "month 4".
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import format from 'date-fns/format';
import gql from 'graphql-tag';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { Link } from 'react-router-dom';
import { graphql } from 'react-apollo';
import '../../../node_modules/bootstrap/dist/css/bootstrap.css';
import './style.css';
import {
ButtonDropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
} from 'reactstrap';
import axios from 'axios';
import TituloSmall, { types } from '../TituloSmall';
const query0 = gql`
query postsDiaComoHoy($dia: Int!, $mes: Int!) {
posts(first: 2, dia: $dia, mes: $mes, categoria: 28) {
rows {
id
fecha_dia_hoy
imagen_intro
titulo
introtext
autor
fulltext
fulltext2
imagen_banner
categoria {
id
}
tags {
id
titulo
}
}
count
}
}
`;
const renderTagItem = item => {
const { id, titulo } = item;
return (
<Link key={id} to={`/tags/${id}/`}>
<div className="tag">{titulo}</div>
</Link>
);
};
const removeTagHtml = valor => valor.replace(/(<([^>]+)>)/g, '');
const removerTwitter = valor => valor.replace(/- #\w+/g, '');
let updated = 0;
let dates = format(Date(), 'D');
let month = format(Date(), 'M');
export class DayScreen extends Component {
constructor(props) {
super(props);
this.state = {
data: this.props,
currentIndex: 0,
sortItem1: month,
sortItem2: dates,
cantidadMeses: [
'Enero',
'Febrero',
'Marzo',
'Abril',
'Mayo',
'Junio',
'Julio',
'Agosto',
'Septiembre',
'Octubre',
'Noviembre',
'Diciembre',
],
diasMes: [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
],
};
}
state = {
items: [],
};
componentDidUpdate() {
this.getArticles();
updated = 0;
}
getArticles = async () => {
const changeArticles = `
{
posts(first: 3, dia: ${this.state.sortItem2}, mes: ${month}) {
rows {
id
fecha_dia_hoy
imagen_intro
titulo
introtext
autor
views
fulltext
fulltext2
imagen_banner
categoria {
id
}
tags{
id
titulo
}
}
count
}
}
`;
if (updated) {
try {
const response = await axios.get(
`http://localhost:4000/graphql/?query=${changeArticles}`,
) .then(response => {
this.setState(() => ({
items: response.data.data.posts.rows,
}));
let { data } = this.props;
const { items } = this.state;
data.posts.rows = items;
return response;
});
// Log the response so we can look at it in the console
// Set the data to the state
} catch (error) {
// If there's an error, set the error to the state
// this.setState(() => ({ error }));
console.log(error);
// console.log(this.state.error);
}
}
};
selectIndex = direction => {
const { currentIndex } = this.state;
const {
data: {
posts: { count },
},
} = this.props;
let nexIndex = currentIndex + direction;
nexIndex = nexIndex < 0 ? count - 1 : nexIndex;
nexIndex = nexIndex >= count ? 0 : nexIndex;
this.setState({ currentIndex: nexIndex });
};
monthSelected() {
const { sortItem1, sortItem2, dropdownOpen1 } = this.state;
this.setState({
dropdownOpen1: !dropdownOpen1,
});
if (dropdownOpen1) {
month = sortItem1;
dates = sortItem2;
updated = 1;
}
}
dateSelected() {
const { sortItem1, sortItem2, dropdownOpen2 } = this.state;
this.setState({
dropdownOpen2: !dropdownOpen2,
});
if (dropdownOpen2) {
month = sortItem1;
dates = sortItem2;
updated = 1;
}
}
onDiasChanged=(e)=>{
this.setState({sortItem2:[...e.currentTarget.innerHTML]});
}
onMesChanged=(e)=>{
this.setState({sortItem1:[...e.currentTarget.innerHTML]});
}
render() {
const { data } = this.props;
if (data.loading) {
return <div>Loading...</div>;
}
if (data.error) {
return <div>{data.error.message}</div>;
}
if (data.posts.rows.length <= 0) {
return <div>Nada que mostrar...</div>;
}
const {
data: {
posts: { rows },
},
} = this.props;
this.items = this.props.data.posts.rows;
const {
currentIndex,
sortItem1,
cantidadMeses,
sortItem2,
dropdownOpen1,
dropdownOpen2,
diasMes,
} = this.state;
const item = rows[currentIndex] ? rows[currentIndex] : rows[0];
const html = item.fulltext + item.fulltext2;
const image = `${process.env.REACT_APP_IMG_BASE}${item.imagen_intro ||
item.imagen_banner}`;
data.variables.mes = sortItem1;
data.variables.dia = sortItem2;
return (
<div className="containerDiaComoHoyNoticia">
<div className="box">
<span />
<span />
<div className="mesTexto">{cantidadMeses[sortItem1 - 1]}</div>
<div className="diaTexto">{sortItem2}</div>
</div>
<div>
<div className="textoContainer">
<div className="tituloDiaComoHoyNoticia">
{'BUSCA QUE OCURRIÓ EL DÍA QUE TU QUIERAS EN EL FÚTBOL'}
</div>
<div className="separatorLinea" />
<div className="listaMesDia">
<span className="circuloMesDia">1</span>
<span>Mes</span>
<ButtonDropdown
isOpen={dropdownOpen1}
toggle={() => {
this.monthSelected();
}}>
<DropdownToggle color="white" caret>
{sortItem1}
</DropdownToggle>
<DropdownMenu>
{cantidadMeses.map((items, i) => (
<DropdownItem
dropDownValue="Mes"
dropDownValue="Mes" onClick={this.onMesChanged}>
{i + 1}
</DropdownItem>
))}
</DropdownMenu>
</ButtonDropdown>
<span className="circuloMesDia">2</span>
<span>Dia</span>
<ButtonDropdown
isOpen={dropdownOpen2}
toggle={() => {
this.dateSelected();
}}>
<DropdownToggle caret>{sortItem2}</DropdownToggle>
<DropdownMenu>
{diasMes.map(i => (
<DropdownItem
dropDownValue="Mes" onClick={this.onDiasChanged}>
{i}
</DropdownItem>
))}
</DropdownMenu>
</ButtonDropdown>
</div>
</div>
</div>
{rows.map(itemArticulo => (
<div className="listaNoticiasContenido">
<img
alt={itemArticulo.titulo}
src={process.env.REACT_APP_IMG_BASE + itemArticulo.imagen_intro}
className="listaNoticiasImagen"
/>
<div className="rectanguloIconoPlay" />
<div className="contenidoArticulo">
<div className="tituloArticulo"><a href="#" onClick = {this.state.currentIndex = 1}>{itemArticulo.titulo}</a></div>
<div className="descripcionArticulo">
{removeTagHtml(itemArticulo.introtext)}
</div>
<div className="escritor">
<div className="nombreAutor">
<div>
<FontAwesomeIcon icon="user-circle" />
<span className="autorArticulo">
{removerTwitter(itemArticulo.autor) || 'Sin autor'}
</span>
<FontAwesomeIcon icon="eye" />
<span className="vistasTotalesArticulos">
{itemArticulo.views}
</span>
<FontAwesomeIcon icon="calendar" />
<span className="cantidadArticulosEscritos">
{itemArticulo.fecha_dia_hoy}
</span>
</div>
</div>
</div>
</div>
<div className="separadorArticulos" />
</div>
))}
<h2 className="tituloDescripcion">{item.titulo}</h2>
<div className="titlesContainer">
<TituloSmall
iconName="user-circle"
label={item.autor || 'Sin autor'}
/>
<TituloSmall
iconName="calendar"
label={format(item.fecha_dia_hoy, 'DD/MM/YYYY')}
/>
</div>
<div className="imageIntro">
<img className="imageDescription" src={image} alt={item.titulo} />
<div className="esquinaFigura">
<div className="boxWhite">
<span />
<span />
<div className="mesTextoBoxWhite">
{cantidadMeses[sortItem1 - 1]}
</div>
<div className="diaTextoBoxWhite">{sortItem2}</div>
</div>
</div>
</div>
<article dangerouslySetInnerHTML={{ __html: html }} />
<TituloSmall iconName="tags" label="Tags" type={types.BIG} />
{item.tags.map(itemsTags => renderTagItem(itemsTags))}
</div>
);
}
}
DayScreen.propTypes = {
data: PropTypes.shape({
loading: PropTypes.bool.isRequired,
currentSortItem: PropTypes.string.isRequired,
error: PropTypes.shape({ message: PropTypes.string }),
}).isRequired,
};
DayScreen.defaultProps = {};
const queryOptions = {
options: () => ({
variables: {
dia: dates,
mes: month,
},
}),
};
export default graphql(query0, queryOptions)(DayScreen);
I want the change of state to be made without pressing double click and the delay that I showed in the image occurs.
Thanks for your help!

You have directly mutated the state and not setting the state using setState method so your render method will not be called at the time of selection and because of it, you will not getting the change immediately once your render method will be call you will get those changes. so your dropdown implementation should be like.
onMessChanged=(e)=>{
this.setState({sortItem2:e.currentTarget.innerHTML});
}
<DropdownMenu>
{diasMes.map(i => (
<DropdownItem
dropDownValue="Mes"
onClick={this.onMessChanged}>
{i}
</DropdownItem>
))}
</DropdownMenu>
As here you are using the reactstrap so it might be possible that your event target may be different so you have to use currentTarget
the currentTarget refers to the element that the event listener directly attached to while the target still refers to the specific element where we clicked.

First error I see is that you can not set the state directly as this.state.sortItem = e.target.innerHTMLInstead you have to use this.setState({ sortItem: e.targetinnerHTML })
Y por favor, intenta no usar Spanglish xD es una mala práctica.

Related

Sum of points with react Custom Rolette and Context API

When the user spins the roulette wheel (Rolette.js) it shows the number of points the user will receive if they get the question right (Quiz.js).
How to make the points count if the user gets the question right or wrong. (If the question is correct, the points of the roulette must be added, if the roulette gives -30, 30 points must be withdrawn, if the user has no points, it must return zero).
- -> DEMO CODE LINK <- -
Play.js -> File Context API
export default function PlayProvider({ children }) {
const [prizeNumber, setPrizeNumber] = useState(0);
const data = [];
return (
<PlayContext.Provider value={{ prizeNumber, setPrizeNumber, data }}>
{children}
</PlayContext.Provider>
);
}
export function usePlay() {
const context = useContext(PlayContext);
const { prizeNumber, setPrizeNumber } = context;
const data = [
{ id: 1, option: 10 },
{ id: 2, option: -30 },
{ id: 3, option: 50 },
{ id: 4, option: 30 },
{ id: 5, option: 40 },
{ id: 6, option: 20 }
];
return { prizeNumber, setPrizeNumber, data };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Rolette.js
import React, { useState } from "react";
import { Wheel } from "react-custom-roulette";
import { Link } from "react-router-dom";
import { usePlay } from "./Play";
export default () => {
const [mustSpin, setMustSpin] = useState(false);
const { prizeNumber, setPrizeNumber, data } = usePlay();
const handleSpinClick = () => {
const newPrizeNumber = Math.floor(Math.random() * data.length);
setPrizeNumber(newPrizeNumber);
setMustSpin(true);
};
return (
<>
<div align="center">
<h1 align="center">Roulette Game</h1>
<hr />
<Wheel
mustStartSpinning={mustSpin}
prizeNumber={prizeNumber}
data={data}
outerBorderColor={["#f2f2f2"]}
outerBorderWidth={[25]}
innerBorderColor={["#f2f2f2"]}
radiusLineColor={["#dedede"]}
radiusLineWidth={[10]}
textColors={["#ffffff"]}
fontSize={[50]}
perpendicularText={[true]}
backgroundColors={[
"#F22B35",
"#F99533",
"#24CA69",
"#514E50",
"#46AEFF",
"#9145B7"
]}
onStopSpinning={() => {
setMustSpin(false);
}}
/>
<button className="button2" onClick={handleSpinClick}>
SPIN
</button>
<br />
{!mustSpin ? data[prizeNumber].option : "0"}
<hr />
<div align="center">
<Link to="/quiz">
<button className="btn2" disabled={mustSpin}>
Answer
</button>
</Link>
<button className="btn2" disabled>
Finish
</button>
</div>
</div>
</>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Quiz.js -> Questions
import React, { useState } from "react";
import { Link } from "react-router-dom";
import { usePlay } from "./Play";
const dat = {
question: "Dummy Question?",
answers: ["A", "B", "C", "D"],
correctAnswer: "B"
};
function Quiz(props) {
// Context API
const { prizeNumber } = usePlay();
const { data } = usePlay();
const [selectedAnswer, setSelectedAnswer] = useState("");
const [isSubmitted, setIsSubmitted] = useState(false);
const [isError, setIsError] = useState(false);
console.log(selectedAnswer);
const onSelectAnswer = (answer) => {
if (isSubmitted) return;
setIsSubmitted(true);
setSelectedAnswer(answer);
setIsError(dat.correctAnswer !== answer);
};
const getAnswerClass = (answer) => {
if (!isSubmitted) {
return "";
} else if (dat.correctAnswer === answer) {
return "correct";
}
return isError ? "incorrect" : "";
};
return (
<div>
<h1 align="center">Questions</h1>
<hr />
<div className="question">
<h3>{dat.question}</h3>
{dat.answers.map((answer) => (
<p
key={answer}
className={getAnswerClass(answer)}
onClick={() => {
onSelectAnswer(answer);
}}
>
{answer}
</p>
))}
<br />
<span align="center" disabled={!isSubmitted}>
{data[prizeNumber].option}/300
</span>
</div>
<hr />
<div align="center">
<Link to="/r2">
<button className="btn2" disabled={!isSubmitted}>
Answer
</button>
</Link>
<button className="btn2" disabled>
Finish
</button>
</div>
</div>
);
}
export default Quiz;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

How to get the promise value in reactjs?

I am trying to render multiple images, stored on firebase, on a single page.
This is the function to get the image url:
async getTokenImage(fileName) {
const ref = firebase.storage().ref('token/' + fileName);
const url = await ref.getDownloadURL();
console.log('in here')
return url
}
This is the function call:
<div
class="card-img-top"
style={{
backgroundColor: '#'+token.color,
backgroundImage: 'url('+this.getTokenImage(token.fileName).then((value) => {return value})+')'
}}></div>
console logging the "value" gives the needed image url
but returning the "value" gives nothing.
for the sake of testing, I have done this:
let image = this.getTokenImage(token.fileName).then((result) => {return result})
console.log(image)
which results in:
So how do I get the image url within the initial function call?
Part of grandfather component:
<MintedTokens
account={this.state.account}
contract={this.state.contract}
tokens={this.state.tokens} />
Father component:
import React from 'react';
import "./minted-tokens.scoped.css";
import MultipleMintedTokens from './multiple-minted-tokens.js';
import SingleMintedTokens from './single-minted-token.js';
class MintedTokens extends React.Component {
render() {
const color = window.location.pathname.split('/')[2]
let display
if(color == undefined) {
display = <MultipleMintedTokens
account={this.props.account}
tokens={this.props.tokens}></MultipleMintedTokens>
} else {
display = <SingleMintedTokens
account={this.props.account}
color={color}
tokens={this.props.tokens}></SingleMintedTokens>
}
return (
<div class="Minted-Token">
{display}
</div>
);
}
}
export default MintedTokens;
Child component (where the multiple images need to be rendered):
import React from 'react';
import ether from '../../assets/ether.svg'
import firebase from "../../firebase.js"
import { Link } from 'react-router-dom';
class MultipleMintedTokens extends React.Component {
async getTokenImage(fileName) {
const ref = firebase.storage().ref('token/' + fileName);
const url = await ref.getDownloadURL();
console.log('in here')
return url
}
render() {
return (
<div class="welcome minted-tokens">
<h1 class="">Minted Tokens</h1>
<div class="row">
{this.props.tokens.map((token, key) => {
let name = '',
description = ''
if(token.to == this.props.account) {
token.name.length >= 17 ? name = token.name.slice(0,17) + '...' : name = token.name
token.description.length >= 28 ? description = token.description.slice(0,29) + '...' : description = token.description
let image = this.getTokenImage(token.fileName).then((result) => {return result})
console.log(image)
return (
<Link to={token.tokenURI} key={key}>
<div class='token-id'>{token.id}</div>
<div class="card card-width">
<div
class="card-img-top"
style={{
backgroundColor: '#'+token.color,
backgroundImage: 'url('+this.getTokenImage(token.fileName).then((value) => {return value})+')'
}}></div>
<h5 class="card-header" style={{
backgroundColor: '#'+token.color,
color: '#'+token.fontColor}}>{name}</h5>
<div class="card-body">
<p class="card-text">{description}</p>
<div class="foot-of-card">
<span class="row price-row">
<img src={ether} alt="ether" class="icon" />
<p class="card-text">{token.price}</p>
</span>
<p class="card-text datetime">{token.dateTime}</p>
</div>
</div>
</div>
</Link>
)
}
})}
</div>
</div>
);
}
}
export default MultipleMintedTokens;
I could not test it well but you can try the following:
Add:
constructor(props) {
super(props);
this.state = {
urlImgs: [],
};
}
...
componentDidMount() {
const { tokens } = this.props;
const promiseArray = tokens.map((token) => getTokenImage(token.fileName));
Promise.all(promiseArray)
.then(valueArray => {
this.setState(prevState => ({
...prevState,
urlImgs: valueArray
}))
})
.catch(err => console.log(err));
}
...
backgroundImage: `url(${urlImgs[key] ?? null})`
All Code:
class MultipleMintedTokens extends React.Component {
constructor(props) {
super(props);
this.state = {
urlImgs: [],
};
}
async getTokenImage(fileName) {
const ref = firebase.storage().ref('token/' + fileName);
const url = await ref.getDownloadURL();
console.log('in here')
return url
}
componentDidMount() {
const { tokens } = this.props;
const promiseArray = tokens.map((token) => getTokenImage(token.fileName));
Promise.all(promiseArray)
.then(valueArray => {
this.setState(prevState => ({
...prevState,
urlImgs: valueArray
}))
})
.catch(err => console.log(err));
}
render() {
const { urlImgs } = this.state;
return (
<div class="welcome minted-tokens">
<h1 class="">Minted Tokens</h1>
<div class="row">
{this.props.tokens.map((token, key) => {
let name = '',
description = ''
if(token.to == this.props.account) {
token.name.length >= 17 ? name = token.name.slice(0,17) + '...' : name = token.name
token.description.length >= 28 ? description = token.description.slice(0,29) + '...' : description = token.description
let image = this.getTokenImage(token.fileName).then((result) => {return result})
console.log(image)
return (
<Link to={token.tokenURI} key={key}>
<div class='token-id'>{token.id}</div>
<div class="card card-width">
<div
class="card-img-top"
style={{
backgroundColor: '#'+token.color,
backgroundImage: `url(${urlImgs[key] ?? null})`
}}></div>
<h5 class="card-header" style={{
backgroundColor: '#'+token.color,
color: '#'+token.fontColor}}>{name}</h5>
<div class="card-body">
<p class="card-text">{description}</p>
<div class="foot-of-card">
<span class="row price-row">
<img src={ether} alt="ether" class="icon" />
<p class="card-text">{token.price}</p>
</span>
<p class="card-text datetime">{token.dateTime}</p>
</div>
</div>
</div>
</Link>
)
}
})}
</div>
</div>
);
}
}
export default MultipleMintedTokens;
if you have React with version > 16.8, I advice you to start using Stateless Components and Hooks. And read about the lifecycle of React and the render method here:

Reactjs Update the state without reload the page

I built a shopping cart in my app. This is the flow:
- The customer sees a list of items and clicks on one he wants;
- The next page is where he chooses the quantity of products and then I save in localStorage;
- By clicking Confirm, he goes to the shopping cart with the same products he has chosen. On this page (shopping cart) he can change the quantity and in this moment the total and quantity must change (see the image).
I was able to do this reloading the page, but when in production the page is not working properly. I need to do this without reload the page.
How to do this without reload the page?
I got 3 components: Header (with the icon cart), ChooseQuantity and Cart.
See below the code:
//My Choose Quantity Component
import React from 'react';
import '../../components/ChooseQuantity/ChooseQuantity.css';
class ChooseQuantity extends React.Component {
constructor(props) {
super(props);
const { lotQuantity, totalQuantity, maxTotalItems, maxPurchase, lot, totalTickets, events, onChange } = this.props;
this.state = {
counter: 0,
lotQuantity: lotQuantity,
totalQuantity: totalQuantity,
maxTotalItems: maxTotalItems,
maxPurchase: maxPurchase,
totalTickets: totalTickets,
onChange: onChange,
events: events,
lot: lot,
tickets: events.tickets,
cart: []
}
this.increment = this.increment.bind(this);
this.decrement = this.decrement.bind(this);
}
componentDidMount() {
// console.log(this.state.lot);
// localStorage.setItem('teste', JSON.stringify(this.state.lotQuantity));
}
// static getDerivedStateFromProps(props, state) {
// console.log(props.lot);
// // console.log(state);
// if (props.selected !== state.selected) {
// return {
// selected: props.selected,
// };
// }
// }
// componentDidUpdate(prevProps, prevState) {
// console.log(this.props.lot);
// localStorage.setItem('teste', JSON.stringify(this.props.lot.quantity));
// if (this.props.lot !== prevProps.lot) {
// // this.selectNew();
// }
// }
async increment() {
await this.setState({
lotQuantity: this.state.lotQuantity + 1,
totalQuantity: + 1,
});
let lotUniqueNumber = this.state.lot.lotUniqueNumber;
let lotQuantity = this.state.lotQuantity;
var ar_lot = [];
this.state.tickets.lot.forEach(function (item) {
if (lotUniqueNumber === item.lotUniqueNumber) {
item.quantity = lotQuantity;
item.total = item.totalLotPrice * item.quantity
}
ar_lot.push(item);
})
// console.log(ar_lot);
//CALCULATING A QUANTITY
var ob_qtd = ar_lot.reduce(function (prevVal, elem) {
const ob_qtd = prevVal + elem.quantity;
return ob_qtd;
}, 0);
await this.setState({ totalTickets: ob_qtd })
//CALCULATING A QUANTITY
//CALCULATING THE TOTAL
var ob_total = ar_lot.reduce(function (prevVal, elem) {
const ob_total = prevVal + elem.total;
return ob_total;
}, 0);
// CALCULATING THE TOTAL
//RIDING THE SHOPPING CART
let total = {
price: ob_total,
totalQuantity: ob_qtd,
};
let tickets = {
name: this.state.tickets.name,
prevenda: this.state.tickets.prevenda,
unique_number: this.state.tickets.unique_number,
lot: ar_lot
}
let events = {
banner_app: this.state.events.banner_app,
installments: this.state.events.installments,
max_purchase: this.state.events.max_purchase,
name: this.state.events.name,
tickets: tickets
}
var cart = { events: events, total: total };
this.setState({
cart: cart
})
// console.log(cart);
localStorage.setItem('cart', JSON.stringify(cart));//RECORDING CART IN LOCALSTORAGE
localStorage.setItem('qtd', JSON.stringify(ob_qtd));
window.location.reload();//UPDATE PAGE FOR CHANGES TO BE UPDATED
}
async decrement() {
await this.setState({
lotQuantity: this.state.lotQuantity - 1,
totalQuantity: - 1,
totalTickets: this.state.totalTickets - 1,
});
let lotUniqueNumber = this.state.lot.lotUniqueNumber;
let lotQuantity = this.state.lotQuantity;
var ar_lot = [];
this.state.tickets.lot.forEach(function (item) {
if (lotUniqueNumber === item.lotUniqueNumber) {
item.quantity = lotQuantity;
item.total = item.totalLotPrice * item.quantity
}
ar_lot.push(item);
})
//CALCULANDO A QUANTIDADE
var ob_qtd = ar_lot.reduce(function (prevVal, elem) {
const ob_qtd = prevVal + elem.quantity;
return ob_qtd;
}, 0);
//CALCULANDO A QUANTIDADE
//CALCULANDO O TOTAL
var ob_total = ar_lot.reduce(function (prevVal, elem) {
const ob_total = prevVal + elem.total;
return ob_total;
}, 0);
//CALCULANDO O TOTAL
let total = {
price: ob_total,
totalQuantity: ob_qtd,
};
let tickets = {
name: this.state.tickets.name,
prevenda: this.state.tickets.prevenda,
unique_number: this.state.tickets.unique_number,
lot: ar_lot
}
let events = {
banner_app: this.state.events.banner_app,
installments: this.state.events.installments,
max_purchase: this.state.events.max_purchase,
name: this.state.events.name,
tickets: tickets
}
var cart = { events: events, total: total };
localStorage.setItem('cart', JSON.stringify(cart));
localStorage.setItem('qtd', JSON.stringify(ob_qtd));
window.location.reload();
}
render() {
return (
<div className="choose-quantity">
{
this.state.lotQuantity <= 0 ?
<div className="space-button"></div> :
<button className='minus' onClick={this.decrement}><i className="fas fa-minus"></i></button>
}
<div id='counter' className="qtd" value={this.state.lotQuantity} onChange={this.onChange}>{this.state.lotQuantity}</div>
{
this.state.totalTickets >= this.state.maxPurchase ?
<div className="space-button"></div> :
<button className="plus" onClick={() => this.increment(this.state.lotQuantity)}><i className="fas fa-plus"></i></button>
}
</div>
)
}
}
export default ChooseQuantity;
//My Shopping Cart Component
import React, { Component } from 'react';
import Swal from "sweetalert2";
import { Link } from 'react-router-dom';
import './Cart.css';
import '../../components/Css/App.css';
import Lot from './Lot';
import ChooseQuantity from './ChooseQuantity';
import Header from '../../components/Header/Header';
import Tabbar from '../../components/Tabbar/Tabbar';
const separator = '/';
class Cart extends Component {
constructor(props) {
super(props);
this.state = {}
this.choosePayment = this.choosePayment.bind(this);
}
async componentDidMount() {
const company_info = JSON.parse(localStorage.getItem('company_info'));
await this.setState({
company_image: company_info.imagem,
company_hash: company_info.numeroUnico,
})
const cart = JSON.parse(localStorage.getItem('cart'));
const total = cart.total;
if(cart){
const {
events,
events: { tickets },
total
} = cart;
await this.setState({
cart,
events,
tickets: tickets,
banner_app: events.banner_app,
eventName: cart.events.name,
priceTotal: total.price,
quantity: total.totalQuantity,
lots: tickets.lot,
maxTotalItems: cart.events.max_purchase,
selectedLots: tickets.lot,
total: total.totalQuantity
});
}
const teste = JSON.parse(localStorage.getItem('teste'))
this.setState({teste: teste})
}
choosePayment() {
Swal.fire({
title: 'Método de Pagamento',
text: 'Qual o médtodo de pagamento que você deseja usar?',
confirmButtonText: 'Cartão de Crédito',
confirmButtonColor: '#007bff',
showCancelButton: true,
cancelButtonText: 'Boleto Bancário',
cancelButtonColor: '#007bff',
}).then((result) => {
if (result.value) {
this.props.history.push('/checkout');
} else{
this.props.history.push('/checkout-bank-slip');
}
})
}
render() {
return (
<div>
<Header Title="Carrinho" ToPage="/" />
{
this.state.total <= 0 ?
<Tabbar />
:
null
}
<div className="cart">
<div className="container-fluid">
{
this.state.total > 0 ?
<div>
<div className="box-price">
<div className="row box-default ">
<div className="col col-price">
<h6>{this.state.quantity} INGRESSO{this.state.quantity > 1 ? 'S' : ''}</h6>
<h5>R$ {parseFloat(this.state.priceTotal).toFixed(2).replace('.', ',')}</h5>
</div>
</div>
</div>
<div className="row">
<div className="col-12 col-image no-padding">
<img src={this.state.banner_app} alt="" />
</div>
</div>
<div className="row">
<div className="col">
<h1 className="event-title text-center">{this.state.eventName}</h1>
</div>
</div>
<div className="padding-15">
{
this.state.lots.map((lot, l) =>
<div key={l}>
{
lot.quantity > 0 ?
<div>
<div className="row">
<div className="col">
<h5 className="ticket-name">{lot.ticketName}</h5>
</div>
</div>
<div className="row">
<div className="col-8">
<h5 className="lot-name">
{ lot.lotName } - ({lot.lotNumber}º Lote)
</h5>
<h6 className="lot-price">
R$ {lot.lotPrice.replace('.', ',')} ({lot.lotPrice.replace('.', ',')} + {lot.lotPriceTax.replace('.', ',')})
</h6>
</div>
<div className="col-4">
<h3 className='lot-big-price'>
{lot.lotPrice.replace('.', ',')}
</h3>
</div>
</div>
<div className="row">
<div className="col align-items">
<ChooseQuantity
lotQuantity={lot.quantity}
maxPurchase={this.state.events.max_purchase}
totalTickets={this.state.total}
lot={lot}
events={this.state.events}
maxTotalItems={this.state.maxTotalItems}
onCLick={this.onClick}
/>
</div>
</div>
</div>
:
null
}
</div>
)
}
<div className="row cart-footer" style={{ marginRight: '-15px', marginLeft: '-15px', backgroundColor: '#f4f7fa' }}>
<button className="col col-purchase" style={{ justifyContent: 'center', alignItems: 'center' }} onClick={this.choosePayment}>
Confirmar Comprar
</button>
</div>
</div>
</div>
:
<div className='padding-15'>
<div className="mt-5 no-margin box-default row">
<div className="col">
<h3 className="text-center">
Não há nenhum item em seu carrinho.
</h3>
<p className="text-center">
Toque no botão <strong>Buscar Eventos</strong> para iniciar uma nova pesquisa.
</p>
<Link className="btn btn-primary btn-block" to="/">
Buscar Eventos
</Link>
</div>
</div>
<div className="row no-margin box-default mt-3">
<div className="col">
<img src={`//www.yeapps.com.br/admin/files/empresa/${this.state.company_hash}/${this.state.company_image}`} alt={`${this.state.company_name}`} />
</div>
</div>
</div>
}
</div>
</div>
</div>
);
}
}
export default Cart;
//My Header Component
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
// import { withRouter } from 'react-router';
import './Header.css';
import BackButton from '../BackButton/BackButton';
class Header extends Component {
constructor(props){
super(props);
this.state = {
qtd: 0
}
}
componentDidMount() {
const qtd = JSON.parse(localStorage.getItem('qtd'));
this.setState({qtd: qtd});
}
render() {
const { Title } = this.props;
return (
<div>
<nav className="navbar">
{ this.props.Title === 'Home' ? null : <BackButton />}
<Link to="/cart" className="icon-cart">
<i className="fas fa-shopping-cart"></i>
<span className="badge badge-danger">
{this.state.qtd}
</span>
</Link>
<div className="navbar-brand">
{Title}
</div>
</nav>
</div>
);
}
}
export default Header;
You need to update your presentational components(Card,Header) state in componentDidUpdate the same way as you did it in componentDidMount. componentDidMount works only one time with first render and there you set your state variables which you use in render. Do the same setState in componentDidUpdate
P.S. but you need to be sure that with counter increasing your presentational components get new props which will trigger componentDidUpdate.In your case you use localStorage but it will be better to pass data through common parent container(the one which holds those 3 components) as props to Card and Header.

How to make use of props in a more efficient way?

I have a code in which I receive the values ​​of two dropdown and then I make a request to my graphql by GET method with AXIOS. I would like to know if I can use props to not do that kind of thing? How could I do it?.
There are two dropdown and if I select the day and the month, I should leave the results without reloading the entire page.
Here are some pictures of how this works:
Select day and/or month:
The result and the request with Axios:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import format from 'date-fns/format';
import gql from 'graphql-tag';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { Link } from 'react-router-dom';
import { graphql } from 'react-apollo';
import Divider from '../Divider';
import TituloSmall, { types } from '../TituloSmall';
import Titulo from '../Titulo';
import '../../../node_modules/bootstrap/dist/css/bootstrap.css';
import './style.css';
import {
ButtonDropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
} from 'reactstrap';
import { addMonths } from 'date-fns';
import axios from 'axios';
const query0 = gql`
query postsDiaComoHoy($dia: Int!, $mes: Int!) {
posts(first: 2, dia: $dia, mes: $mes, categoria: 28) {
rows {
id
fecha_dia_hoy
imagen_intro
titulo
introtext
autor
fulltext
fulltext2
imagen_banner
categoria {
id
}
tags {
id
titulo
}
}
count
}
}
`;
const renderTagItem = item => {
const { id, titulo } = item;
return (
<Link key={id} to={`/tags/${id}/`}>
<div className="tag">{titulo}</div>
</Link>
);
};
const removeTagHtml = valor => valor.replace(/(<([^>]+)>)/g, '');
const removerTwitter = valor => valor.replace(/- #\w+/g, '');
var updated = 0;
var dates = format(Date(), 'D'),
month = format(Date(), 'M');
export class dayScreen extends Component {
constructor(props) {
super(props);
this.state = {
currentIndex: 0,
sortItem1: month,
sortItem2: dates,
cantidadMeses: [
'Enero',
'Febrero',
'Marzo',
'Abril',
'Mayo',
'Junio',
'Julio',
'Agosto',
'Septiembre',
'Octubre',
'Noviembre',
'Diciembre',
],
diasMes: [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
],
};
}
state = {
error: null,
items: [],
};
componentDidUpdate() {
this.getAnime();
this.render();
updated = 0;
}
getAnime = async () => {
const changeArticles = `
{
posts(first: 3, dia: ${dates}, mes: ${month}) {
rows {
id
fecha_dia_hoy
imagen_intro
titulo
introtext
autor
views
fulltext
fulltext2
imagen_banner
categoria {
id
}
tags{
id
titulo
}
}
count
}
}
`;
if (updated) {
try {
const response = await axios.get(
'http://localhost:4000/graphql/?query=' + changeArticles,
);
// Log the response so we can look at it in the console
// Set the data to the state
this.setState(() => ({
isLoaded: true,
items: response.data.data.posts.rows,
}));
this.props.data.posts.rows = this.state.items;
} catch (error) {
// If there's an error, set the error to the state
this.setState(() => ({ error }));
console.log(this.state.error);
}
}
};
selectIndex = direction => {
const { currentIndex } = this.state;
const {
data: {
posts: { count },
},
} = this.props;
let nexIndex = currentIndex + direction;
nexIndex = nexIndex < 0 ? count - 1 : nexIndex;
nexIndex = nexIndex >= count ? 0 : nexIndex;
this.setState({ currentIndex: nexIndex });
};
monthSelected() {
this.setState({
dropdownOpen1: !this.state.dropdownOpen1,
});
if (this.state.dropdownOpen1) {
this.props.data.variables.mes = this.state.sortItem1;
this.props.data.variables.dia = this.state.sortItem2;
month = this.state.sortItem1;
dates = this.state.sortItem2;
updated = 1;
}
}
dateSelected() {
this.setState({
dropdownOpen2: !this.state.dropdownOpen2,
});
if (this.state.dropdownOpen2) {
this.props.data.variables.mes = this.state.sortItem1;
this.props.data.variables.dia = this.state.sortItem2;
month = this.state.sortItem1;
dates = this.state.sortItem2;
updated = 1;
}
}
render() {
const { data } = this.props;
if (data.loading) {
return <div>Loading...</div>;
}
if (data.error) {
return <div>{data.error.message}</div>;
}
if (data.posts.rows.length <= 0) {
return <div>Nada que mostrar...</div>;
}
const {
data: {
posts: { rows },
},
} = this.props;
const { currentIndex } = this.state;
const item = rows[currentIndex];
let html = item.fulltext + item.fulltext2;
const description = item.introtext.replace(/(<([^>]+)>)/gi, '');
const image = `${process.env.REACT_APP_IMG_BASE}${item.imagen_intro ||
item.imagen_banner}`;
return (
<div className="containerDiaComoHoyNoticia">
<div className="box">
<span />
<span />
<div className="mesTexto">
{this.state.cantidadMeses[this.state.sortItem1 - 1]}
</div>
<div className="diaTexto">{this.state.sortItem2}</div>
</div>
<div>
<div className="textoContainer">
<div className="tituloDiaComoHoyNoticia">
{'BUSCA QUE OCURRIÓ EL DÍA QUE TU QUIERAS EN EL FÚTBOL'}
</div>
<div className="separatorLinea"></div>
<div className="listaMesDia">
<span className="circuloMesDia">1</span>
<span>Mes</span>
<ButtonDropdown
isOpen={this.state.dropdownOpen1}
toggle={() => {
this.monthSelected();
}}>
<DropdownToggle color="white" caret>
{this.state.sortItem1}
</DropdownToggle>
<DropdownMenu>
{this.state.cantidadMeses.map((items, i) => (
<DropdownItem
dropDownValue="Mes"
onClick={e => {
this.state.sortItem1 = e.target.innerHTML;
}}>
{i + 1}
</DropdownItem>
))}
</DropdownMenu>
</ButtonDropdown>
<span className="circuloMesDia">2</span>
<span>Dia</span>
<ButtonDropdown
isOpen={this.state.dropdownOpen2}
toggle={() => {
this.dateSelected();
}}>
<DropdownToggle caret>{this.state.sortItem2}</DropdownToggle>
<DropdownMenu>
{this.state.diasMes.map(i => (
<DropdownItem
dropDownValue="Mes"
onClick={e => {
this.state.sortItem2 = e.target.innerHTML;
}}>
{i}
</DropdownItem>
))}
</DropdownMenu>
</ButtonDropdown>
</div>
</div>
</div>
{rows.map((item, index) => (
<div className="listaNoticiasContenido">
<img
alt={item.titulo}
src={process.env.REACT_APP_IMG_BASE + item.imagen_intro}
className="listaNoticiasImagen"
/>
<div className="rectanguloIconoPlay"></div>
<div className="contenidoArticulo">
<div className="tituloArticulo">{item.titulo}</div>
<div className="descripcionArticulo">
{removeTagHtml(item.introtext)}
</div>
<div className="escritor">
<div className="nombreAutor">
<div>
<FontAwesomeIcon icon="user-circle" />
<span className="autorArticulo">
{removerTwitter(item.autor) || 'Sin autor'}
</span>
<FontAwesomeIcon icon="eye" />
<span className="vistasTotalesArticulos">{item.views}</span>
<FontAwesomeIcon icon="calendar" />
<span className="cantidadArticulosEscritos">
{item.fecha_dia_hoy}
</span>
</div>
</div>
</div>
</div> <div className="separadorArticulos"></div>
</div>
))}
<h2 className="titulo">{item.titulo}</h2>
<div className="titlesContainer">
<TituloSmall
iconName="user-circle"
label={item.autor || 'Sin autor'}
/>
<TituloSmall
iconName="calendar"
label={format(item.fecha_dia_hoy, 'DD/MM/YYYY')}
/>
</div>
<div className="imageIntro">
<img className="imageDescription" src={image} alt={item.titulo} />
<div class="esquinaFigura">
<div className="boxWhite">
<span />
<span />
<div className="mesTextoBoxWhite">
{this.state.cantidadMeses[this.state.sortItem1 - 1]}
</div>
<div className="diaTextoBoxWhite">{this.state.sortItem2}</div>
</div>
</div>
</div>
<article dangerouslySetInnerHTML={{ __html: html }} />
<TituloSmall iconName="tags" label="Tags" type={types.BIG} />
{item.tags.map(item => renderTagItem(item))}
</div>
);
}
}
dayScreen.propTypes = {
data: PropTypes.shape({
loading: PropTypes.bool.isRequired,
error: PropTypes.shape({ message: PropTypes.string }),
}).isRequired,
};
dayScreen.defaultProps = {};
const queryOptions = {
options: () => ({
variables: {
dia: dates,
mes: month,
},
}),
};
export default graphql(query0, queryOptions)(dayScreen);
How could I do this without Axios? When doing it with Axios, is this scalable? I have been told that the props are for that, but I do not know how to do it.
I would like to do this without Axios and only using props. Receive the value of the dropdowns and change that part of the page doing the query with graphql.
You can do this by implementing Apollo Client, start by installing Apollo and then set it up in your project following the documentation.

Refactor code to not have setState Html

Here's my current code :
(2 Files & Classes : "FoodStandComponent.jsx")
/* ************************************* */
/* ******** IMPORTS ******** */
/* ************************************* */
import uuid from 'uuid/v4';
import { Card, CardBlock, Button, InputGroup, Input } from 'reactstrap';
import React, { Component } from 'react';
import ProviderInfos from '../ProviderInfos/ProviderInfos';
import InputType from './InputType/InputType';
/* ************************************* */
/* ******** VARIABLES ******** */
/* ************************************* */
const propTypes = {
newInput: React.PropTypes.array,
exportInput: React.PropTypes.func,
};
/* ************************************* */
/* ******** COMPONENT ******** */
/* ************************************* */
class FoodStandComponent extends Component {
constructor(props) {
super(props);
this.state = {
newInput: [
{ name: 'Pretzel', id: uuid() },
{ name: 'Curry', id: uuid() },
{ name: 'Wurst', id: uuid() },
],
InValue: '',
};
this.add = this.add.bind(this);
this.remove = this.remove.bind(this);
}
add = (name) => {
const ninput = this.state.newInput.concat({ name, id: uuid(), value: this.state.InValue });
this.setState({
newInput: ninput,
InValue: '',
});
};
remove = (id, name) => {
const toBeRemoved = this.state.newInput.filter(x => x.name === name).pop();
if (toBeRemoved) {
this.setState({
newInput: this.state.newInput.filter(x => x.name !== name).concat(
this.state.newInput.filter(x => x.name === name && x.id !== toBeRemoved.id),
),
});
}
};
render() {
console.log();
const cubeFifteenOrUnder = this.state.newInput.filter(x => x.name === 'Pretzel')
&& this.state.newInput.filter(x => x.name === 'Pretzel').length <= 13;
const dsoFifteenOrUnder = this.state.newInput.filter(x => x.name === 'Curry')
&& this.state.newInput.filter(x => x.name === 'Curry').length <= 13;
const multiFifteenOrUnder = this.state.newInput.filter(name => name === 'Wurst')
&& this.state.newInput.filter(x => x.name === 'Wurst').length <= 13;
return (
<Card>
<CardBlock className="main-table">
<fieldset>
<legend>Pretzels</legend>
<InputGroup>
<Input placeholder="Pretzel" />
<ProviderInfos type="Pretzel" />
{ cubeFifteenOrUnder && (
<div className="plus" onClick={() => this.add('Pretzel')}>
<i className="fa fa-plus" aria-hidden="true" />
</div>
) }
{ !cubeFifteenOrUnder && (
<div className="plus-off">
<i className="fa fa-plus" aria-hidden="true" />
</div>
) }
</InputGroup>
{this.state.newInput.map((mapStorageVariable) => {
if (mapStorageVariable.name === 'Pretzel') {
return (<InputType
id={mapStorageVariable.id}
placeholder={mapStorageVariable.name}
value={mapStorageVariable.value}
onRemove={() => this.remove(mapStorageVariable.id, mapStorageVariable.name)}
/>);
}
return null;
})}
</fieldset>
<fieldset>
<legend>Curries</legend>
<InputGroup>
<Input placeholder="Curry" />
<ProviderInfos type="Curry" />
{ dsoFifteenOrUnder && (
<div className="plus" onClick={() => this.add('Curry')}>
<i className="fa fa-plus" aria-hidden="true" />
</div>
) }
{ !dsoFifteenOrUnder && (
<div className="plus-off">
<i className="fa fa-plus" aria-hidden="true" />
</div>
) }
</InputGroup>
{this.state.newInput.map((mapStorageVariable) => {
if (mapStorageVariable.name === 'Curry') {
return (<InputType
id={mapStorageVariable.id}
placeholder={mapStorageVariable.name}
value={mapStorageVariable.value}
onRemove={() => this.remove(mapStorageVariable.id, mapStorageVariable.name)}
/>);
}
return null;
})}
</fieldset>
<fieldset>
<legend>Wursts</legend>
<InputGroup>
<Input placeholder="Wurst" />
<ProviderInfos type="Wurst" />
{ multiFifteenOrUnder && (
<div className="plus" onClick={() => this.add('Wurst')}>
<i className="fa fa-plus" aria-hidden="true" />
</div>
) }
{ !multiFifteenOrUnder && (
<div className="plus-off">
<i className="fa fa-plus" aria-hidden="true" />
</div>
) }
</InputGroup>
{this.state.newInput.map((mapStorageVariable) => {
if (mapStorageVariable.name === 'Wurst') {
return (<InputType
id={mapStorageVariable.id}
placeholder={mapStorageVariable.name}
value={mapStorageVariable.value}
onRemove={() => this.remove(mapStorageVariable.id, mapStorageVariable.name)}
/>);
}
return null;
})}
</fieldset>
<Button color="secondary">Options</Button>{' '}
<Button id="btn">Exécuter</Button>
</CardBlock>
</Card>
);
}
}
SearchExtendedComponent.propTypes = propTypes;
export default SearchExtendedComponent;
(and InputTypeComponent.jsx )
/* ************************************* */
/* ******** IMPORTS ******** */
/* ************************************* */
import ProviderInfos from '../../ProviderInfos/ProviderInfos';
import React, { Component } from 'react';
import { Card, CardBlock, Button, InputGroup, Input } from 'reactstrap';
/* ************************************* */
/* ******** VARIABLES ******** */
/* ************************************* */
/* ************************************* */
/* ******** COMPONENT ******** */
/* ************************************* */
export default class InputTypeComponent extends Component {
constructor(props) {
super(props);
this.state = {
type: '',
};
}
onRemove = () => {
this.props.onRemove(this.props.id);
}
onChange = () => {
this.props.onChange(this.props.id);
}
render() {
const { placeholder, id, value } = this.props;
const { type } = this.state;
this.type = placeholder;
return (
<InputGroup key={id}>
<Input placeholder={placeholder} />{value}
<ProviderInfos type={this.type} />
<div className="minus" onClick={this.onRemove}>
<i className="fa fa-minus" aria-hidden="true" />
</div>
</InputGroup>
);
}
}
I'm trying to get a list with "add" and "remove" buttons refactored into one function.
as you can see above thanks to #Jacky Choo's answer & code I'm almost there but the issue is that I've lost the functionality I previously had of having the line I want deleted removed when I click on it's own remove button.
When I click on this minus sign the line with the text and changed checkboxes stays.
and the very last line dissapears.
UPDATE :
Fixed it!
By changing the remove to this I get my intended result. yes the lines below the deleted one are reset but that is for Redux to handle. A big shoutout to #Jacky Choo who basically figured it out for me!
remove = (id, name) => {
this.setState({
newInput: this.state.newInput.filter(x => x.name === name && x.id !== id),
});
};
Tested working on my side (replaced some customized class to normal input box which is not provided)
Adding jsx into the state doesn't seem right, I've amended the code to store food as an array in the state, each of them is mapped to the component that renders the input field.
Hope it helps
import React, { Component } from 'react';
const FoodInput = ({ foodName, id }) => {
return (
<input placeholder={foodName} key={id} />
);
}
export default class PretzelStandComponent extends Component {
constructor(props) {
super(props);
const uuid = require('uuid/v1');
this.state = {
Foods: [
{name: "Pretzel", id: uuid()},
{name: "Curry", id: uuid()},
{name: "Wurst", id: uuid()}
]
}
}
componentDidMount() {
}
addFood(name) {
const uuid = require('uuid/v1');
this.setState({
Foods: this.state.Foods.concat({ name, id: uuid() })
});
}
removeFood(name) {
var foodToBeRemoved = this.state.Foods.filter(x => x.name === name).pop()
if (foodToBeRemoved){
this.setState({
Foods: this.state.Foods.filter(x => x.name !== name).concat(
this.state.Foods.filter(x => x.name === name && x.id !== foodToBeRemoved.id)
)
});
}
}
render() {
return (
<div>
<fieldset>
<legend>Pretzels</legend>
{this.state.Foods.map(food => {
if (food.name === "Pretzel") {
return (<FoodInput foodName={food.name} key={food.id} {...food} />)
}
else
{
return null
}
})}
<button onClick={() => this.addFood("Pretzel")}>Add a Pretzel</button>
<button onClick={() => this.removeFood("Pretzel")}>Remove a Pretzel</button>
</fieldset>
<fieldset>
<legend>Curry</legend>
{this.state.Foods.map(food => {
if (food.name === "Curry") {
return (<FoodInput foodName={food.name} key={food.id} {...food} />)
}
else
{
return null
}
})}
<button onClick={() => this.addFood("Curry")}>Add a Curry</button>
<button onClick={() => this.removeFood("Curry")}>Remove a Curry</button>
</fieldset>
<fieldset>
<legend>Wurst</legend>
{this.state.Foods.map(food => {
if (food.name === "Wurst") {
return (<FoodInput foodName={food.name} key={food.id} {...food} />)
}
else
{
return null
}
})}
<button onClick={() => this.addFood("Wurst")}>Add a Wurst</button>
<button onClick={() => this.removeFood("Wurst")}>Remove a Wurst</button>
</fieldset>
</div>
);
}
}
You could do smth like this:
export default class PretzelStandComponent extends Component {
constructor(props) {
super(props);
this.state = {
handler: 1
};
...
}
handleHTML = () => {
switch(this.state.handler){
case 1:
return this.returnHTML();
}
}
//Set handlerVariable in your functions instead of setting html
//Return html
returnHTML = () => {
return (<div/>);
}
render(){
return(<div>{this.handleHTML()}</div>);
}
The arguably best and easiest solution is to have an array responsible of storing for each of the ingredients, and then map through each of the arrays in the render.
What's more is that you can use just one function for incrementing or decrementing your arrays because all they do is just create a new uuid, but they return the same JSX more or less.
Because of this similarity you can use just these two functions and the only parameter is just the name of the ingredient to add/remove from.
Here's a working demo. I have replaced some of the components, such as <Input /> and <ProviderInfos /> with a <span> just for the demo.
I also replaced your uuid() with a fake key to get it working.
class PretzelStandComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
inputPretzel: [],
inputCurry: [],
inputWurst: []
};
this.increment = this.increment.bind(this);
this.decrement = this.decrement.bind(this);
}
increment = (name) => {
//const uuid = require('uuid/v1');
//uuid();
let uuid = this.state['input' + name].length+1;
let n = this.state['input' + name].slice();
n.push(uuid);
this.setState({['input' + name]: n});
}
decrement = (name) => {
let n = this.state['input' + name];
n.pop();
this.setState({['input' + name]: n});
}
render() {
return (
<div>
<div className="main-table">
<fieldset>
<legend>Pretzels</legend>
{this.state.inputPretzel.map(
key => {
return <span>{key}</span>;
})
}
<button onClick={this.increment.bind(this, "Pretzel")}>Add a Pretzel</button>
<button onClick={this.decrement.bind(this, "Pretzel")}>Remove a Pretzel</button>
</fieldset>
<fieldset>
<legend>Curry</legend>
{this.state.inputCurry.map(
key => {
return <span>{key}</span>;
})
}
<button onClick={this.increment.bind(this, "Curry")}>Add Curry</button>
<button onClick={this.decrement.bind(this, "Curry")}>Remove Curry</button>
</fieldset>
<fieldset>
<legend>Wurst</legend>
{this.state.inputWurst.map(
key => {
return <span>{key}</span>;
})
}
<button onClick={this.increment.bind(this, "Wurst")}>Add Wurst</button>
<button onClick={this.decrement.bind(this, "Wurst")}>Remove Wurst</button>
</fieldset>
<button color="secondary">Options</button>{' '}
<button id="btn">Exécuter</button>
</div>
</div>
);
}
}
ReactDOM.render(<PretzelStandComponent />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Resources