React how to implement case opening animation - javascript

import { useEffect, useState } from "react"
import { useParams } from "react-router-dom"
import robux from "../images/robux.png"
import CaseItem from "../Components/CaseItem"
export default function CaseOpening() {
const chosenCase = useParams().case
console.log(chosenCase)
const items = [1, 2, 3, 4, 5, 6, 1]
//we have a param, lets see if its a valid case!
return (
<div className="case-open-container">
<h2 className="case-title">{chosenCase}</h2>
<div className="case-price">
<div className="case-price-in mx-3">53,155</div>
<img className="sell-robux" src={robux} ></img>
</div>
<div className="case-area">
<div className="arrow-down"></div>
<div className="case-items" style={{ overflow: "visible" }}>
{items.map((item, index) =>
<CaseItem
key={index}
title={"Eerie Pumpkin Head"}
price={"59,421"}
image={'https://rest-bf.blox.land/render/1158416'}
></CaseItem>
)}
</div>
<div className="arrow-up"></div>
</div>
</div >
)
}
I want to create a case opening animation like so when a user clicks a button to spin this will spin and randomly pick an item. Does anyone have any ideas for how I could implement something like this in React I honestly don't even know where to begin.

Related

How to load a video in ReactPlayer when clicking a div that is fetching data from JSON file?

So I'm pretty much new in React/Web development and just can't figure it out regarding ReactPlayer.
I have a .JSON file with [ID, Question, URL] and I load the questions into divs. What I want is when I click the div(question) then the URL that is assigned to that question should load in the ReactPlayer..
This is how it looks so far:
import React, { useState } from "react";
import Questions from "../data/questions.json";
import style from "./Card.module.css";
import ReactPlayer from "react-player/youtube";
function Card() {
const handleClick = (item) => {
console.log(item);
};
return (
<div>
<div className={style.ViewContent}>
<div className={style.mainCard}>
{ListQuestions.map((ListItem, index) => {
return (
<div onClick={() => handleClick(ListItem.url)} key={index} className={style.Card}>
<h3 className={style.Titel}>{ListItem.question}</h3>
</div>
);
})}
</div>
<div className={style.VideoPlayer}>
<ReactPlayer url={handleClick.item} controls={true} />
</div>
</div>
</div>
);
}
export default Card;
I tested the click function and every time I click the question the console logs only the URL.
But how can the ReactPlayer get that URL and play the video?
I'm sorry for the bad coding.. still learning :)
I tried adding onSubmit on the div box so when clicking the div it should submit/load the link to the ReactPlayer... but thinking logically and then interpreting it kind of does not work.
I figured it out :D
import React, { useState } from "react";
import Questions from "../data/questions.json";
import style from "./Card.module.css";
import ReactPlayer from "react-player";
function Card() {
const [playUrl, setPlayUrl] = useState(""); ← here you could put the youtube link to show up when loading the page.
const [isPlaying, setIsPlaying] = useState(true);
return (
<div>
<div className={style.ViewContent}>
<div className={style.mainCard}>
{ListQuestions.map((ListItem, index) => {
return (
<div onClick={() => setPlayUrl(ListItem.url)} key={index} className={style.Card}>
<h3 className={style.Titel}>{ListItem.question}</h3>
</div>
);
})}
</div>
<div className={style.VideoPlayer}>
<ReactPlayer url={playUrl} controls={true} playing={isPlaying} />
</div>
</div>
</div>
);
}
export default Card;

Dynamic import of react-icons

Is it possible to import dynamically react-icons if each of icon is a separate component?
My code looks like this:
import React from 'react';
import { Icon1, Icon2, Icon3, Icon4 } from 'react-icons/ri';
const Foo = () => (
<div className="xxx">
<div className="y">
<Icon1 />
</div>
<div className="y">
<Icon2 />
</div>
<div className="y">
<Icon3 />
</div>
<div className="y">
<Icon4 />
</div>
</div>
);
export default Foo;
and would want it to look close to this:
import React from 'react';
const Buttons = () => {
const iconsList = ['Icon1', 'Icon2', 'Icon3'];
const renderIcon = (icon) => {
const Icon = icon;
return (
<div className="y">
<Icon />
</div>
)
}
return (
<div className="d-flex align-items-center justify-content-end">
{iconsList.map(icon => renderIcon(icon))}
</div>
)
};
export default Buttons;
The problem I face is how to make the import of icons work there if I didn't want to import all icons using *.
Also the problem is that if I make
import { Icon1, Icon2, Icon3, Icon4 } from 'react-icons/ri'
at the top, it still doesn't work for the second version of code.
You have to replace the strings values of your icons in the iconsList array with the Icon component itself.
Just change :
const iconsList = ['Icon1', 'Icon2', 'Icon3'];
to :
const iconsList = [Icon1, Icon2, Icon3];
And add a key to prevent Each child in a list should have a unique "key" prop.Warning like this :
{iconsList.map((icon, index) => renderIcon(icon, index))}
and :
const renderIcon = (icon, index) => {
const Icon = icon;
return (
<div className="y" key={index}>
<Icon />
</div>
);
};
this is an example in codesandbox
Note : If you import all icons using * , you're importing hundreds of icons at once which is probably not ideal.

I don't know why I get this, if it is according to the React manual

I tell him I am transferring an event from the component
child ( ItemCount) to the parent component parent ItemDetail the onADD event that only acts if an item is passed to it and when it does, the state becomes true.
The child has an event called add to cart which triggers the event and passes a product counter.
It runs perfectly but it throws me a warning that is the following.
react-dom.development.js:86 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
Can you tell me the mistake and what I did wrong? from now very grateful
I share the codes Thanks
ItemCount (component child)
import React, { useState, useContext} from 'react';
import 'materialize-css/dist/css/materialize.css';
import '../App.css';
import {FontAwesomeIcon} from '#fortawesome/react-fontawesome';
import {faPlus, faMinus, faPowerOff} from '#fortawesome/free-solid-svg-icons';
import {contextoProducto} from './ProductContext';
import swal from 'sweetalert';
const ItemCount = ({item, stockInitial, initial = 0, onAdd}) => {
const [contador, setContador] = useState(initial)
const [stock, setStock] = useState(stockInitial)
const { addProduct } = useContext(contextoProducto);
const sumar = () => {
setContador(contador + 1)
setStock(stock - 1);
avisarStock();
}
const restar= () => {
if(contador > 0){
setContador(contador - 1);
setStock(stock + 1);
}
else
{
setContador(0);
}
}
const reset = () =>{
setContador(0);
setStock(stockInitial);
}
const avisarStock = () => {
if(stock > 0 ){
}
else{
swal('No podemos enviar su envio no hay stock', "Gracias", "error");
setStock(0);
setContador(contador)
}
}
const agregarAlCarrito = () => {
onAdd(contador);
}
return(
<div>
<div className=" row left text">Stock: {stock}</div>
<article>{contador}</article>
<div className="buttonCount">
<button onClick={sumar}>
<FontAwesomeIcon icon ={faPlus}/>
</button>
<button onClick={restar}>
<FontAwesomeIcon icon={faMinus}/>
</button>
<button onClick={reset}>
<FontAwesomeIcon icon={faPowerOff}/>
</button>
<br/><h2>{avisarStock}</h2>
<button onClick={() => addProduct({...item, quantity: contador}) || agregarAlCarrito()} > Agregar al carrito </button>
</div>
</div>
)
}
export default ItemCount;
ItemDetail (component father)
import React, { useState } from "react";
import '../App.css';
import 'materialize-css/dist/css/materialize.css';
import Count from './ItemCount';
import { Link } from "react-router-dom";
export const ItemDetail = ({item}) => {
const [itemSell, setItemSell] = useState(false);
const onAdd = (count) => {
setItemSell(true);
}
return (
<main className="itemsdetails">
<div className="row" id= {item.id}>
<div className="col s12 m6">
<img src={item.image} alt="item" className="itemImg responsive-img"/>
</div>
<div className="col s12 m6">
<div className="col s12">
<h5 className="itemName">{item.title}</h5>
</div>
<div className="col s12">
<p className="itemDescription">{item.description}</p>
</div>
<div className="col s12">
<p className="itemPrice"> {item.price}</p>
</div>
<div className="col s12">
{
itemSell ? <Link to="/cart"><button className="waves-effect waves-light btn-large">Finalizar Compra</button></Link> : <Count item= {item} stockInitial={item.stock} onAdd= { onAdd } />
}
</div>
</div>
</div>
</main>
)
};
export default ItemDetail;
<br/><h2>{avisarStock}</h2>
Here, you are trying to render a component, but actually avisarStock is a function which sets state and opens an alert. It makes no sense to try to render this function.
It would appear you meant to render stock not avisarStock. This would show your stock state in the <h2>:
<br/><h2>{stock}</h2>
<br/><h2>{avisarStock}</h2> avisarStock is a function, and since Component can be function, react thinks you are doing Component instead of <Component />

React state is undefined when fetching data from sanity cms

I followed a tutorial recently about integrating a cms into your website. The tutorial used sanity cms which made the process very intuitive. Once I was done with the tutorial I was ready to use it in my own projects.
however when I try to fetch data with the useEffect hook I get an error: Cannot read properties of undefined. I know this is because fetching data is done async. But the thing I can't wrap my head around is I did it the exact same way as the tutorial. He didn't use any state for loading or isFetched. So my question is what did I do different than the tutorial and how should I solve it?
I don't really want to use a loading state because that doesn't really look that good...
This is the JSON object I receive from the api:
[{…}]
0:
buttonlabel: "Start learning"
description: "Ranging from beginner to pro level tricks. Wanna know the best way to learn a trick? You can search for it down below and find a tutorial from one of our trainers as well as a detailed explanation. Still stuck? Come ask us at a Westsite training moment."
intro: "Welcome to the Westsite trick progression guide. Here you can find a collection of all the wakeboarding tricks you can think of. "
_createdAt: "2022-05-24T16:26:13Z"
_id: "a4f8cf02-4b86-44d5-a63d-c95a3a7d3293"
_rev: "QYLgvM20Eo53w3noOOj0MB"
_type: "hero"
_updatedAt: "2022-05-24T17:29:10Z"
This is the tutorial component:
import React, { useState, useEffect } from "react";
import { motion } from "framer-motion";
import { urlFor, client } from "../../client";
import { AppWrap, MotionWrap } from "../../wrapper";
import "./About.scss";
const About = () => {
const [abouts, setAbouts] = useState([]);
useEffect(() => {
const query = '*[_type == "abouts"]';
client.fetch(query).then((data) => setAbouts(data));
}, []);
return (
<div>
<h2 className="head-text">
I know that
<span> Good Design </span>
<br />
means
<span> Good Business</span>
</h2>
<div className="app__profiles">
{abouts.map((about, index) => {
return (
<motion.div
whileInView={{ opacity: 1 }}
whileHover={{ scale: 1.1 }}
transition={{ duration: 0.5, type: "tween" }}
className="app__profile-item"
key={about.title + index}
>
<img src={urlFor(about.imgUrl)} alt={about.title} />
<h2 className="bold-text" style={{ marginTop: 20 }}>
{about.title}
</h2>
<p className="p-text" style={{ marginTop: 10 }}>
{about.description}
</p>
</motion.div>
);
})}
</div>
</div>
);
};
export default AppWrap(
MotionWrap(About, "app__about"),
"about",
"app__whitebg"
);
And this is mine:
import React, { useState, useEffect } from "react";
import { motion } from "framer-motion";
import { BiRightArrowAlt } from "react-icons/bi";
import { client } from "../../client";
import "./Hero.scss";
const Hero = () => {
const [heroContent, setHeroContent] = useState([]);
useEffect(() => {
const query = '*[_type == "hero"]';
client.fetch(query).then((data) => setHeroContent(data));
}, []);
const content = heroContent[0];
return (
<div className="app__hero">
<motion.div
className="app__hero-content-container"
whileInView={{ opacity: [0, 1], x: [500, 0] }}
transition={{ duration: 1, ease: "easeOut" }}
>
<div className="app__hero-content">
<h2 className="heading-text">
Learn
<span className="highlighted"> wakeboarding </span>
the right way
</h2>
<p className="p-text">{content.intro}</p>
<p className="p-text">{content.description}</p>
<button className="primary-btn p-text app__flex">
{content.buttonlabel}
<BiRightArrowAlt />
</button>
</div>
</motion.div>
</div>
);
};
export default Hero;
This line will cause issues before the data is applied to state asynchronously
const content = heroContent[0];
On the initial render, heroContent is an empty array, so content will be undefined until your data is loaded. A couple options -
1 - render some sort of loading state until heroContent has been populated -
if (!heroContent.length) return <LoadingSpinner />
2 - wrap the portion that is trying to use content with a guard clause
{content && (
<p className="p-text">{content.intro}</p>
<p className="p-text">{content.description}</p>
<button className="primary-btn p-text app__flex">
{content.buttonlabel}
<BiRightArrowAlt />
</button>
)}
The issue comes when you try to access properties from content when it's undefined. If you don't want to show any loading indicator, I would go with showing some fallback for when content is not defined. e.g.
Instead of:
<p className="p-text">{content.intro}</p>
You could go with:
<p className="p-text">{content?.intro ?? '-'}</p>
or something like that.
Problem is that you breakdown your state on different level that create problem with state changes. So, you have to do this
Either you call state as map function or save your state with specfic index 0.
import React, { useState, useEffect } from "react";
import { motion } from "framer-motion";
import { BiRightArrowAlt } from "react-icons/bi";
import { client } from "../../client";
import "./Hero.scss";
const Hero = () => {
const [heroContent, setHeroContent] = useState([]);
useEffect(() => {
const query = '*[_type == "hero"]';
// this is giving response as array
client.fetch(query).then((data) => setHeroContent(data));
}, []);
return (
<div className="app__hero">
{heroContent.map((content,index)=>
<motion.div
className="app__hero-content-container"
whileInView={{ opacity: [0, 1], x: [500, 0] }}
transition={{ duration: 1, ease: "easeOut" }}
key={index}
>
<div className="app__hero-content">
<h2 className="heading-text">
Learn
<span className="highlighted"> wakeboarding </span>
the right way
</h2>
<p className="p-text">{content.intro}</p>
<p className="p-text">{content.description}</p>
<button className="primary-btn p-text app__flex">
{content.buttonlabel}
<BiRightArrowAlt />
</button>
</div>
</motion.div>}
</div>
);
};
export default Hero;

Why when passing parameters from one component to another it arrives undefined and then arrives again with the data?

As will be shown below when passing properties from a parent component to a child component my code is executed first before the properties arrive and when trying to do a .map of an Array it returns the error "Cannot read properties of undefined (reading 'map')". Why does this happen?
As you can see in the image, first you get undefined values which generates the error in the .map and then you get the properties
Parent component:
import React, {useEffect, useState} from "react";
import ItemDetail from "./itemDetail";
import '../../App.css';
import { useParams } from "react-router-dom";
//Component Class
const ItemDetailContainer = () => {
const [producto, productos] = useState([]);
const { productId } = useParams();
useEffect(() => {
fetch('http://localhost:3000/productos/' + productId)
.then(res=>res.json())
.then(data=>productos(data))
}, [productId]);
console.log(producto);
return (
<div className="container">
<ItemDetail
nombre={producto.nombre}
id={producto.id}
precio={producto.precio}
category={producto.category}
imagenes={producto.imagenes}
ancho={producto.ancho}
alto={producto.alto} />
</div>
)
}
export default ItemDetailContainer;
Child component:
import React from 'react';
import { Card } from 'react-bootstrap';
import ItemCount from '../itemCount';
const ItemDetail = ({ nombre, id, precio, category, imagenes, ancho, alto }) => {
console.log(imagenes);
return (
<div className="row" key={id} id={id}>
<div className="col-md-6" id="productImage">
<div className="carousel-item">
{imagenes.map((p) => (
<img src={p} className="d-block w-100" alt={nombre} />
))}
</div>
</div>
<div className="col-md-6 producto">
<div className="card">
<Card.Body>
<Card.Title>{nombre}</Card.Title>
<Card.Text>{category}</Card.Text>
<Card.Text>${precio}</Card.Text>
<ItemCount />
</Card.Body>
</div>
</div>
</div>
);
};
export default ItemDetail;
Change your code to only execute if imagenes is an array. Personally I would rethink how you are structuring your initial state. Instead of it being an empty array, perhaps make it an object with all of those properties having default values.
<div className="carousel-item">
{ Array.isArray(imagenes) && imagenes.map((p) => (
<img src={p} className="d-block w-100" alt={nombre} />
))}
</div>

Categories