Im building a small gadget for a website that uses react. But its giving me a reference error when it says that my variable "combinations" is not defined as well that there is a TypeError: wrapper is null. It works but at the same time its giving a constant error.
import React from 'react';
import './portfolio.css';
const wrapper = document.getElementById("wrapper");
console.log(wrapper)
const rand = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);
const uniqueRand = (min, max, prev) => {
let next = prev;
while(prev === next) next = rand(min, max);
return next;
}
const combinations = [
{ configuration: 1, roundness: 1 },
{ configuration: 1, roundness: 2 },
{ configuration: 1, roundness: 3 },
{ configuration: 2, roundness: 2 },
{ configuration: 2, roundness: 3 }
];
let prev = 0;
setInterval(() => {
const index = uniqueRand(0, combinations.length - 1, prev),
combination = combinations[index];
wrapper.dataset.configuration = combination.configuration;
wrapper.dataset.roundness = combination.roundness;
prev = index;
}, 3000);
const Portfolio = () => {
return (
<div className='RO__portfolio'>
<div className='RO__portfolio-content' data-roundness="1" data-configuration ="1" id='wrapper'>
<div className='RO__portfolio-content_shape'></div>
<div className='RO__portfolio-content_shape'></div>
<div className='RO__portfolio-content_shape'></div>
<div className='RO__portfolio-content_shape'></div>
<div className='RO__portfolio-content_shape'></div>
<div className='RO__portfolio-content_shape'></div>
<div className='RO__portfolio-content_shape'></div>
</div>
</div>
)
}
export default Portfolio
It should not be giving this to errors:
Uncaught ReferenceError: combinations is not defined
Uncaught TypeError: wrapper is null
Related
Whilst I am doing cart in react, I have no idea why I keep getting NaN value - only from a specific object data.
When I have the following data list:
#1 ItemsList.js
export const ItemsList = [
{
id: 1,
name: "VA-11 Hall-A: Cyberpunk Bartender Action",
price: 110000,
image: cover1,
link: "https://store.steampowered.com/app/447530/VA11_HallA_Cyberpunk_Bartender_Action/?l=koreana",
},
...
{
id: 6,
name: "Limbus Company",
price: 110000,
image: cover6,
link: "https://limbuscompany.com/",
},
];
And the following code, please look at the comment line.
#2 Goods.jsx
import React, { useContext } from "react";
import "./Goods.css";
import { DataContext } from "../../components/context/DataContext";
export const Goods = (props) => {
const { id, name, price, image, link } = props.shopItemProps;
const { cartItems, addItemToCart, removeItemFromCart } =
useContext(DataContext);
const cartItemStored = cartItems[id];
return (
<div className="goods">
<div className="goods-id">{id}</div>
<img src={image} alt="thumbnail_image" className="goods-image" />
<div className="goods-name">{name}</div>
<div className="goods-price">${price}</div>
<button>
<a href={link} className="goods-link">
Official Store Page
</a>
</button>
<div className="cart-button">
<button onClick={() => removeItemFromCart(id)}>-</button>
// ★Maybe here? but why do I get NaN only for id:6? Others work well.
{cartItemStored > -1 && <> ({cartItemStored}) </>}
<button onClick={() => addItemToCart(id)}>+</button>
</div>
</div>
);
};
What should I do to solve NaN? There seems to be no way to make that value as int in this case. Or do you see any problem from the above code block?
Edited
Sorry for confusing you. Here are the additional code related.
#3. DataContext.js (where cartItems state exists)
import React, { createContext, useState } from "react";
import { ItemsList } from "../ItemsList";
export const DataContext = createContext(null);
const getDefaultCart = () => {
let cart = {};
for (let i = 1; i < ItemsList.length; i++) {
cart[i] = 0;
}
return cart;
};
export const DataContextProvider = (props) => {
const [cartItems, setCartItems] = useState(getDefaultCart);
const checkoutTotalSum = () => {
let totalAmount = 0;
for (const item in cartItems) {
if (cartItems[item] > 0) {
let itemInfo = ItemsList.find((product) => product.id === Number(item));
totalAmount += cartItems[item] * itemInfo.price;
}
}
return totalAmount;
};
const addItemToCart = (itemId) => {
setCartItems((prev) => ({ ...prev, [itemId]: prev[itemId] + 1 }));
};
const removeItemFromCart = (itemId) => {
setCartItems((prev) => ({ ...prev, [itemId]: prev[itemId] - 1 }));
};
const updateCartItemCount = (newAmount, itemId) => {
setCartItems((prev) => ({ ...prev, [itemId]: newAmount }));
};
const contextValue = {
cartItems,
addItemToCart,
removeItemFromCart,
updateCartItemCount,
checkoutTotalSum,
};
// console.log(cartItems);
return (
<DataContext.Provider value={contextValue}>
{props.children}
</DataContext.Provider>
);
};
The issue is in the function you are using to set the initial value of cartItems, more specifically, in the for loop. This line is the culprit: i < ItemsList.length, when in your case, it should be i <= ItemsList.length. Why? because you are not including the last element of ItemsList on the cart object (you are initializing the i counter with 1 and ItemsList's length is 6).
So, when you call addItemToCart:
const addItemToCart = (itemId) => {
setCartItems((prev) => ({ ...prev, [itemId]: prev[itemId] + 1 }));
};
And try to update the value corresponding to the last element of ItemsList which is 6 in cartItems, you're getting: '6': undefined + 1 because again, you did skip the last element in the for loop. This results in NaN.
You also have the option of initializing i with 0 and preserve this line: i < ItemsList.length, or:
for (let i = 1; i < ItemsList.length + 1; i++) {
...
}
First of all, I created this example before to connect with API
const enterprises = [
{
address: 'Barueri, São Paulo',
org_name: 'Innova',
enterprise_name: 'Made Lab',
footage: 'Possui 300m²',
enterprise_type: 'Loteamento',
quantity: 'Qnt. dispoíveis: 4',
img_url: [
{
key: 1,
src:
'https://media.discordapp.net/attachments/462727233895661570/938506736065716294/unknown.png',
},
{
key: 2,
src:
'https://media.discordapp.net/attachments/462727233895661570/938506703715053628/unknown.png',
},
],
},
];
And I also created this carousel component
import { useState } from 'react';
import { CarouselWrapper, Slide, ArrowLeft, ArrowRight } from './styled';
import P from 'prop-types';
const ImgCarousel = ({ slides }) => {
const [current, setCurrent] = useState(0);
const length = slides.length;
const nextSlide = () => {
setCurrent(current === length - 1 ? 0 : current + 1);
};
const prevSlide = () => {
setCurrent(current === 0 ? length - 1 : current - 1);
};
if (!Array.isArray(slides) || slides.length <= 0) {
return null;
}
return (
<CarouselWrapper>
{slides.map((slide, index) => {
return (
index === current && (
<Slide key={index} url={slide.image}>
<ArrowLeft onClick={prevSlide} />
<ArrowRight onClick={nextSlide} />
</Slide>
)
);
})}
</CarouselWrapper>
);
};
ImgCarousel.propTypes = {
slides: P.array,
};
export default ImgCarousel;
I know I need to scroll and get the lenght of the image and I did that, but I'm having trouble to add the images into the code behind:
<CardImg>
// HERE
<ImgCarousel src={img_url} key={} />
</CardImg>
Can anybody help me with that?
I have an array of images inside refData. I then map them into an array of img objects with RefItem. I then want thouse specifc images to change to the next one in a line - so img 0 becomes 1, and 1 becomes 2 - as written in refbox. I just cannot figure this one out.. I just want to update the individual numbers in each array item?
import React, {useState, useEffect} from 'react'
import refData from './refData'
import RefItem from './refItem'
function ReferencesPP(){
const refItems = refData.map(item => <RefItem key={item.id} pitem={item}/>)
const [refs, setRefs] = useState([0, 1, 2, 3])
useEffect(() => {
const intervalId = setTimeout(() => {
for(let i = 0; i < refs.length; i++){
if(refs[i] !== refData.length){
setRefs(...refs[i], refs[i] = refs[i] + 1)
} else {
setRefs(...refs[i], refs[i] = 0)
}
}
}, 2000);
return () => clearTimeout(intervalId);
}, [refs]);
return(
<div className="referencespp-container">
<div className="background-container" />
<div className="content-container">
<div id="refbox">
{refItems[refs[0]]}
{refItems[refs[1]]}
{refItems[refs[2]]}
{refItems[refs[3]]}
</div>
</div>
</div>
)
}
export default ReferencesPP
I thought it would be as simple, as writing
const refs = [0, 1, 2, 3]
useEffect(() => {
const intervalId = setInterval(() => {
for(let i = 0; i < refs.length; i++){
if(refs[i] !== refData.length){
refs[i] = refs[i] + 1;
} else {
refs[i] = 0;
}
}
}, 2000);
return () => clearInterval(intervalId);
}, []);
but doing that only updates the const and not the {refItems[refs[0]]} elements?
Have a look at this https://jsfiddle.net/gwbo4pdu/ I think it's what you want to get
React.useEffect(() => {
const intervalId = setTimeout(() => {
const newRefs = [...refs]
const i = newRefs.shift()
newRefs.push(i)
setRefs(newRefs);
}, 2000);
return () => clearTimeout(intervalId);
}, [refs]);
P.S. you can do just newRefs.push(newRefs.shift())
I have the following component:-
import React, { useState, useEffect } from "react"
import Card from "./Card"
import joker from "../../assets/joker.png"
import goalie from "../../assets/goalie.png"
import defender from "../../assets/defender.png"
import midfielder from "../../assets/midfielder.png"
import attacker from "../../assets/attacker.png"
const CardsBoard = () => {
const deckLimits = {
joker: 4, goalkeepers: 12, defenders: 12, midfielders: 12, attackers: 12
};
const [ratingObj, setRatingObj] = useState({});
const [visible1, setVisible1 ] = useState(false);
const [visible2, setVisible2 ] = useState(false);
const [deck, setDeck] = useState([]);
const [deck1, setDeck1] = useState([]);
const [deck2, setDeck2] = useState([]);
const [currCardPl1, setCurrCardPl1] = useState({});
const [currCardPl2, setCurrCardPl2] = useState({});
useEffect(() => {
generateDeck();
distributeCards();
}, [deck]);
const startGame = () => {
//reset decks
setDeck([]);
setDeck1([]);x
setDeck2([]);
//generate the card’s values
generateDeck();
if (deck.length > 0) {
distributeCards();
if (currCardPl1 != undefined){
console.log(currCardPl1);
//unMask ratings of Player 1
setVisible1(true);
setVisible2(false);
}
}
};
const distributeCards = () => {
//randomize the deck
deck.sort(() => Math.random() - 0.5);
//distribute 26 cards at random when the game start
const splitDeck1 = deck.slice(0, 26);
const splitDeck2 = deck.slice(26, 52);
//add this card to the deck
splitDeck1.map((card) => {
setDeck1(deck1 => [...deck1, card]);
});
//add this card to the deck
splitDeck2.map((card) => {
setDeck2(deck2 => [...deck2, card]);
});
//queue the first card to Player 1
setCurrCardPl1(deck1[0]);
//queue the first card to Player 2
setCurrCardPl2(deck2[0]);
};
const generateDeck = () => {
for (let i = 0; i < deckLimits.joker; i++) {
generateCard('joker');
};
for (let i = 0; i < deckLimits.goalkeepers; i++) {
generateCard('goalkeeper');
};
for (let i = 0; i < deckLimits.defenders; i++) {
generateCard('defender');
};
for (let i = 0; i < deckLimits.midfielders; i++) {
generateCard('midfielder');
};
for (let i = 0; i < deckLimits.attackers; i++) {
generateCard('attacker');
};
}
const generateCard = item => {
const card = {
player: 0,
image: getImage(item),
title: item.toUpperCase(),
ratings: [
{ title: "Handling", rating: "99" },
{ title: "Reflexes", rating: "99" },
{ title: "Defending", rating: "99" },
{ title: "Strength", rating: "99" },
{ title: "Passing", rating: "99" },
{ title: "Flair", rating: "99" },
{ title: "Finishing", rating: "99" },
{ title: "Composure", rating: "99" },
],
}
//add this card to the deck
setDeck(deck => [...deck, card]);
}
const getImage = item => {
switch (item) {
case "joker":
return joker;
case "goalkeeper":
return goalie;
case "defender":
return defender;
case "midfielder":
return midfielder;
case "attacker":
return attacker;
default:
break;
}
};
return (
<div className="container-fluid justify-content-center">
<div className="row">
<div className="col-md-6">
<div>
<h4>Player 1</h4>
</div>
<Card
cardInfo={currCardPl1}
showRatings={visible1}
onClick={ratingObj => setRatingObj(ratingObj)}
/>
</div>
<div className="col-md-6">
<h4>Player 2</h4>
<Card
cardInfo={currCardPl2}
showRatings={visible2}
onClick={ratingObj => setRatingObj(ratingObj)}
/>
</div>
</div>
<div className="row top-buffer">
<div className="col-md-12 text-center">
<button
id="startGameBtn"
name="StartGameButton"
className="btn btn-secondary"
onClick={() => startGame()}
>
START GAME
</button>
</div>
</div>
</div>
)
}
export default CardsBoard
And I am getting the error:-
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
I am suspecting it has to do something with the Submit button (onClick) which is calling the setState multiple times, however I cannot seem to fix the problem.
So I have the following questions :-
How can I fix the onClick()?
I would like to click on the Start Game button, and trigger generateDeck(); and distributeCards(); so that I get the deck, deck1 and deck2 filled up. Is there a way to do it? At the moment I have created a useEffect() which is dependant on the deck being filled up, is that the correct way to doing it with hooks?
Thanks for your help and time!
You have deck as a dependency in your useEffect hook. That means generateDeck will run every time the deck is updated. However, generateDeck calls generateCard, which calls setDeck. That causes deck to change, which means you're stuck in a sort of infinite loop. You should tie generateDeck to the onClick handler or some other event which will not be triggered by deck changing.
Also, be careful with this:
deck.sort(() => Math.random() - 0.5)
Calling sort will mutate your state directly, which is something you should avoid in React. Try something like setDeck(d=>[...d].sort(/* Your sorting function here */)) instead.
You are using setDeck() in distrubuteCards and in your useEffect hook, you call again the distributeCards
const distributeCards = () => {
// bla bla
setDeck(deck => [...deck, card]);
}
Which results in calling the hook all the time.
useEffect(() => {
generateDeck();
distributeCards();
}, [deck]);
deck.sort(() => Math.random() - 0.5);
You have a problem here.
Save it inside a variable. Otherwise you update the state all the time it's called.
I have successfully implemented an incrementer app that shows a number with a + and - on each side. When either is clicked, the number goes up or down respectively. But because if statements work differently in jsx I am having trouble setting limits for the number, such as not going below zero.
I have tried putting in if statements but they don't work. How can I make it for instance so if the + or - is clicked once the number reaches a certain min or max value it doesn't change?
class App extends Component {
constructor () {
super()
this.state = {
num: 1
}
this.addNum = this.addNum.bind(this)
this.minusNum = this.minusNum.bind(this)
}
addNum() {
this.setState({
num: this.state.num +1
}, function() {
console.log('number of issues is ' + this.state.num)
})
}
minusNum() {
this.setState({
num: this.state.num - 1
}, function() {
})
}
`
render() {
return (
<div>
<body>
<div className="incrementer">
<div>
<h2 className="minus" onClick={this.minusNum}>-</h2>
</div>
<div>
<h2 className="number">{this.state.num}</h2>
</div>
<div>
<h2 className="plus" onClick={this.addNum}>+</h2>
</div>
</div>
</body>
</div>
);
}
}
export default App;
You should implement your own logic to control edge cases which you don't want to happen.
Here is your code with additional functionality and ES6 arrow functions (without bind).
To change max and min numbers just edit minValue and maxValue
import React from 'react'
class App extends React.Component {
state = {
num: 1
}
minValue = 0
maxValue = 10
addNum = () => {
const { num } = this.state
if (num < this.maxValue) {
this.setState({ num: num + 1 }, this.log)
}
}
minusNum = () => {
const { num } = this.state
if (num > this.minValue) {
this.setState({ num: num - 1 }, this.log)
}
}
log = () => {
console.log('number of issues is ' + this.state.num)
}
render() {
return (
<div className="incrementer">
<div>
<h2 className="minus" onClick={this.minusNum}>
-
</h2>
</div>
<div>
<h2 className="number">{this.state.num}</h2>
</div>
<div>
<h2 className="plus" onClick={this.addNum}>
+
</h2>
</div>
</div>
)
}
}
export default App
Check the bounds of the variable in your addNum and minusNum methods.
There are no “inbuilt” ways to implement state constraints in React.js (in the way one might with e.g. a database column).
Just add a check in your minus function, if the current value in state is zero, do nothing.
this.state = {
num: 1,
minValue: 0,
maxValue: 10
}
minusNum() {
if (this.state.num === this.state.minValue) {
return;
}
this.setState({
num: this.state.num - 1
}, function() {})
}
addNum() {
// assuming you have maxValue in state
if (this.state.num > this.state.maxValue) {
return;
}
this.setState({
num: this.state.num + 1
}, function() {
console.log('number of issues is ' + this.state.num)
})
}