Sum of points with react Custom Rolette and Context API - reactjs

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>

Related

REACT.JS how to detect only one of the cards is clicked from a component

I tried to add click handler on my code, the idea is when i click on my first card, the first card add new class "selected" nad when i click on my third card or else the third card or else will add new class "selected". There is a problem when i was clicking on any card it was always first card was selected. Please help me. Thank you.
Parent code
import React, { useState } from 'react';
import CardBus from '../CardBus/CardBus.component';
import './BusSelector.style.css'
function BusSelector() {
const [buses, setBuses] = useState([
{
busNumber: 1,
destination: 'Cibiru - Cicaheum',
stopTime: '09:20 - 09.45',
stopLocation: 'Jl.Jendral Sudirman',
isSelected: false
},
{
busNumber: 2,
destination: 'Cicaheum - Cibereum',
stopTime: '09:10 - 09.20',
stopLocation: 'Jl.Soekarno Hatta',
isSelected: false
},
]);
return (
<div className="bus-selector--container">
{buses.map((bus) => {
return <CardBus key={bus.busNumber} eachBus={bus} buses={buses} setBuses={setBuses} />
})}
</div>
);
}
export default BusSelector;
Child code:
import React from 'react';
import './CardBus.style.css';
import TimeProgressThin from '../../icon/Time_progress_thin.svg';
import PinLight from '../../icon/Pin_light_thin.svg';
function CardBus(props) {
const [isSelected, setIsSelected] = useState(false)
let { eachBus, buses, setBuses} = props;
const selectedHandler = () => {
if (isSelected) {
const card = document.querySelector('.card');
card.classList.add('selected');
return setIsSelected(!isSelected);
}
else {
const card = document.querySelector('.card');
card.classList.remove('selected');
return setIsSelected(!isSelected);
}
}
return (
<div key={eachBus.key} className="card" onClick={selectedHandler}>
<div className="bus--left">
<h1>{eachBus.busNumber}</h1>
</div>
<div className="bus--right">
<div className="title">
<h1>{`Armada ${eachBus.busNumber}`}</h1>
<h2>{eachBus.destination}</h2>
</div>
<div className="detail">
<div className="detail--item">
<div>
<img src={TimeProgressThin} alt="Time Progress Logo" />
</div>
<div className="detail_content">
<h3>Last stopped</h3>
<h3>{eachBus.stopTime}</h3>
</div>
</div>
<div className="detail--item">
<div>
<img src={PinLight} alt="Pin Light Logo" />
</div>
<div className="detail_content">
<h3>Location Stopped</h3>
<h3>{eachBus.stopLocation}</h3>
</div>
</div>
</div>
</div>
</div>
);
}
export default CardBus;
Allow multiple selections
function CardBus(props) {
const [isSelected, setIsSelected] = useState(false);
let { eachBus, buses, setBuses } = props;
return (
<div key={eachBus.key} className={`card ${isSelected ? 'selected' : ''}`} onClick={() => setIsSelected(!isSelected)}>
...
</div>
);
}
export default CardBus;
Allow single select
You can simplify the code a lot if you move the selected child logic to the parent.
Parent code:
function BusSelector() {
const [buses, setBuses] = useState([
{
busNumber: 1,
destination: 'Cibiru - Cicaheum',
stopTime: '09:20 - 09.45',
stopLocation: 'Jl.Jendral Sudirman',
isSelected: false
},
{
busNumber: 2,
destination: 'Cicaheum - Cibereum',
stopTime: '09:10 - 09.20',
stopLocation: 'Jl.Soekarno Hatta',
isSelected: false
},
]);
const [selectedBus, setSelectedBus] = useState(-1);
return (
<div className="bus-selector--container">
{buses.map((bus) => {
return <CardBus
key={bus.busNumber}
eachBus={bus}
buses={buses}
setBuses={setBuses}
onClick={() => setSelectedBus(bus.busNumber)}
isSelected={bus.busNumber === selectedBus} />;
})}
</div>
);
}
export default BusSelector;
Child code:
function CardBus(props) {
let { eachBus, isSelected, buses, setBuses, onClick } = props;
return (
<div key={eachBus.key} className={`card ${isSelected ? 'selected' : ''}`} onClick={onClick}>
...
</div>
);
}
export default CardBus;

How I can resolve this error message in react? Cannot read property 'details' of null

Hello Stackoverflow community!
I'am practicing with react. I am building a very simple shopping cart system. With the app you can select from products. It adds to the shoppingcart. I'm got this error message: TypeError: Cannot read property 'details' of null.
I'am attaching my code.
App.js
import React, {useState, useEffect } from "react";
import Shop from "./Shop";
import Cart from "./Cart"
const ShoppingItems = [{
id: 1,
details: {
type: "cloth",
name: "Blue jacket",
price: 15000
}
},
{
id: 2,
details: {
type: "cloth",
name: "Trousers",
price: 9990
}
},
{
id: 3,
details: {
type: "cloth",
name: "T-shirt",
price: 5000
}
}
];
const App = () => {
const [selectedItem, setSelectedItem] = useState(null);
useEffect(() => {console.log(selectedItem)}, [selectedItem]);
return(
<div className="ui container">
<Shop Shopitems={ShoppingItems} setSelectedItem={setSelectedItem}/>
<Cart selectedItem={selectedItem}/>
</div>
);
};
export default App;
Shop.js
import React from "react";
const Shop = ({Shopitems, setSelectedItem}) => {
const AddItem = (id) => {
const selectedItem = Shopitems.find( item => item.id === id);
if(selectedItem)
{
setSelectedItem(selectedItem);
}
return;
};
const renderedItems = Shopitems.map((shopitem) => {
return(
<div key={shopitem.id} className="card">
<div className="content">
<div className="header">{shopitem.details.name}</div>
<div className="description">
{shopitem.details.price + " Ft"}
</div>
</div>
<div onClick={() => AddItem(shopitem.id)} className="ui bottom attached button">
<i className="cart icon"></i>
Add to cart
</div>
</div>
);
});
return (
<div className="ui cards">{renderedItems}</div>
);
};
export default Shop;
Cart.js
import React, {useState, useEffect} from "react";
const Cart = ({selectedItem}) => {
const [shoppingCart, setShoppingCart] = useState([]);
useEffect(() => {
//Adding to the shopping cart when an element selected
setShoppingCart([...shoppingCart, selectedItem]);
}, [selectedItem]);
const renderedItems = shoppingCart.map((item) => {
return(
<ul>
<li key={item.id}>
<div className="item">
{item.details.name}
</div>
</li>
</ul>
);
});
return(
<div>
<h1>Shopping Cart</h1>
{renderedItems}
</div>
);
};
export default Cart;
You need to verify that selectItem is not null because you cannot use .map on null, it needs to be an array ([]).
change you code to
import logo from './logo.svg';
import './App.css';
import { useEffect, useState } from 'react';
import Records from './Records';
import Shop from "./Shop";
import Cart from "./Cart"
const ShoppingItems = [{
id: 1,
details: {
type: "cloth",
name: "Blue jacket",
price: 15000
}
},
{
id: 2,
details: {
type: "cloth",
name: "Trousers",
price: 9990
}
},
{
id: 3,
details: {
type: "cloth",
name: "T-shirt",
price: 5000
}
}
];
const App = () => {
const [selectedItem, setSelectedItem] = useState(null);
useEffect(() => {console.log(selectedItem)}, [selectedItem]);
return(
<div className="ui container">
{selectedItem !== null ? <><Shop Shopitems={ShoppingItems} setSelectedItem={setSelectedItem}/> <Cart selectedItem={selectedItem}/> </>: <></>}
</div>
);
};
export default App;
This wil render without error but it is blanc page because you pass 'null' as value.
It may not be a value for the first time. To solve this problem, you can bet where you have this error:for example:
const renderedItems = Shopitems?Shopitems.map((shopitem) => {
return(
<div key={shopitem.id} className="card">
<div className="content">
<div className="header">{shopitem.details.name}</div>
<div className="description">
{shopitem.details.price + " Ft"}
</div>
</div>
<div onClick={() => AddItem(shopitem.id)} className="ui bottom attached button">
<i className="cart icon"></i>
Add to cart
</div>
</div>
);
}) :[] ;
return (
<div className="ui cards">{renderedItems}</div>
);
};
export default Shop;
'

React Need to toggle a div when an edit is clicked for one object in json array(open/Close)

I have a json array and i am iterating array and show the list ,each have its own id.
Each having edit button and when you click on edit ,it shoudl show a div ,inside div i have a dummy text,like wise when i click the edit of next object from JSON array,already openend div of previous object should close and the new JSON object edit div should toggle
<div>
<li key={contact.id}>
<p>{contact.firstName} {contact.lastName}</p>
<p>{contact.email}</p>
<button onClick={() => this.removeContact(contact.id)}>Remove</button>
<button onClick={() => this.showEditDiv(contact.id)}>Edit</button>
<div className="">
<p>This is edit form</p>
</div>
</li>
</div>
Any live demo or jsfiddle will be highly grateful and appreciated
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [activeCurrentDiv, setActiveCurrentDiv] = useState(null);
const [list, setList] = useState([
{
id: 1,
firstName: "john",
email: "sample1#gmail.com"
},
{
id: 2,
firstName: "harry",
email: "sampleharry#gmail.com"
},
{
id: 3,
firstName: "halk",
email: "spiderman#gmail.com"
}
]);
const removeContact = id => {
const filteredList = list.filter(item => {
return item.id !== id;
});
setList(filteredList);
};
const showEditDiv = id => {
setActiveCurrentDiv(id);
};
return (
<div className="App">
<ul>
{list.map((contact, key) => {
return (
<li key={contact.id}>
<p>
{contact.firstName} {contact.lastName}
</p>
<p>{contact.email}</p>
<button onClick={() => removeContact(contact.id)}>Remove</button>
<button onClick={() => showEditDiv(contact.id)}>Edit</button>
<div className={(activeCurrentDiv === contact.id ? "show" : "") + " myDiv"}>
<p>This is edit form</p>
</div>
</li>
);
})}
</ul>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
.App {
font-family: sans-serif;
text-align: center;
}
ul {
list-style: none;
}
ul li {
border-bottom: 1px solid #eaeaea;
}
.myDiv {
display: none;
}
.myDiv.show {
display: block;
}
<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>
You can use "contant.id" and check if it is equals to the "current_id" in my case "activeCurrentDiv" it's time to show that div.
and each user clicks on Edit u save the "current_id/activeCurrentDiv"
working Example: https://codesandbox.io/s/admiring-sound-t9t5r
Live example
Code:
import * as React from "react";
import { render } from "react-dom";
import "./styles.css";
const data = [
{
id: 1,
email: "asf#asdf.com",
firstName: "Anna",
lastName: "L name"
},
{
id: 2,
email: "asf1#asdf.com",
firstName: "Jan",
lastName: "L name 2"
}
];
function App() {
const [isOpen, setIsOpen] = React.useState<number[]>([]);
const showEditDiv = (id: number) => {
if(isOpen.includes(id)) {
setIsOpen([...isOpen.filter(listId => listId !== id )]);
return;
}
setIsOpen([...isOpen, id]);
};
const removeContact = (id: number) => {}
return (
<div className="App">
<ul>
{data.map(contact => (
<div>
<li key={contact.id}>
<p>
{contact.firstName} {contact.lastName}
</p>
<p>{contact.email}</p>
<button onClick={() => removeContact(contact.id)}>
Remove
</button>
<button onClick={() => showEditDiv(contact.id)}>Edit</button>
{isOpen.includes(contact.id) && (
<div>
<p>This is edit form</p>
</div>
)}
</li>
</div>
))}
</ul>
</div>
);
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);

How to perform the mutation of dropdowns status in 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.

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.

Resources