I am about to make a function where you can choose sizes. It works when you use just JavaScript with HTML. Is my syntax from the JavaScript function correct? Because I am getting an Error from Next.js.
Here is the error message I am getting from Next.js.
import React from "react";
const ChangeSize = () => {
const sizes = document.querySelectorAll(".size");
function changeSize() {
sizes.forEach((size) => size.classList.remove("active"));
this.classList.add("active");
}
sizes.forEach((size) => size.addEventListener("click", changeSize));
return (
<div className='size-container'>
<h3 className='title'>size</h3>
<div className='sizes'>
<span className='size'>7</span>
<span className='size'>8</span>
<span className='size active'>9</span>
<span className='size'>10</span>
<span className='size'>11</span>
</div>
</div>
);
};
export default ChangeSize;
normally you wouldn't use the JavaScript DOM API to accomplish this type of task in React. The function and JSX would resemble something like this in a React Function component:
const SizeSwitcher = () => {
const [activeLink, setActiveLink] = React.useState(9); // 9 was default in example
return (
<div className='size-container'>
<h3 className='title'>size</h3>
<div className='sizes'>
<span onClick={() => setActiveLink(7)} className={`size ${activeLink === 7 ? 'active' : ''}`}>7</span>
<span onClick={() => setActiveLink(8)} className={`size ${activeLink === 8 ? 'active' : ''}`}>8</span>
<span onClick={() => setActiveLink(9)} className={`size ${activeLink === 9 ? 'active' : ''}`}>9</span>
<span onClick={() => setActiveLink(10)} className={`size ${activeLink === 10 ? 'active' : ''}`}>10</span>
<span onClick={() => setActiveLink(11)} className={`size ${activeLink === 11 ? 'active' : ''}`}>11</span>
</div>
</div>
);
};
export default SizeSwitcher;
You can state up some state and then use that piece of state to determine if the active class should be present. Next steps could be figuring out how to reduce the code duplication in the example. Hope this helps!
Edit - Oh yeah if you are using Next.js you can leave out the React import at the top. That is handled by Next automatically.
Related
This should be easy but of course I can't figure it out :)
Basically I've implemented a "load more" button when there are more items to display from array but when it reaches the end, I'd like to hide it. The code below doesn't work and I have a feeling it's because it need to check the index of the array and if it's at the end, then hide the button but I am unsure of how to go about the syntax. Thanks
import { useState } from 'react'
import releases from "../data/releases.json";
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import '../main.css'
const Release = () => {
// get first 12 items in array & load next 12 with "see more button"
const STEP = 12;
const [items, setItems] = useState(releases.slice(0, STEP));
const loadMore = () => {
setItems([...items, ...releases.slice(items.length, items.length + STEP)]);
};
return (
<Wrapper>
<div className="release fadein">
{items.map((item, i) => (
<div className="item" key={i}>
<Link to={`/release/${item.id}`}>
<img src={item.imageURL} alt={item.artist} />
</Link>
</div>
))}
{/* code that isn't working here */}
{items ? <button onClick={loadMore} className="btn" > show more </button> : <button className="btn hidden" ></button>}
</div>
</Wrapper >
)
}
when the items are less than 12 the button will not be displayed
{items%12 ===0 ? <button onClick={loadMore} className="btn" > show more </button> : nul}
I'm a newbie in react. I have two class in css file. One is btn and another is active. I want to set an active class to the first button by default and when I click on other buttons it'll be remove and add to the current button. I'll be thankful if anyone help me about this. Thanks in advance.
Here is my codes
import React, {useState} from 'react';
const Tab = () => {
const [tabBtn, setTabBtn] = useState(false);
const handleBtn = () => {
setTabBtn(true);
}
return (
<div className='btnContainer'>
<button className={"btn" + (tabBtn ? " active" : "")} onClick={handleBtn}>One</button>
<button className='btn'>Two</button>
<button className='btn'>Three</button>
<button className='btn'>Four</button>
<button className='btn'>Five</button>
<button className='btn'>Six</button>
<button className='btn'>Seven</button>
</div>
);
}
export default Tab;
Use this code :
className={`btn ${tabBtn ? " active" : ""}`}
So let's make a few optimizations here:
First let's put an array of all your buttons and then use state to track which one is selected.
import React, {useState} from 'react';
const buttonList = ['One', 'Two', 'Three', 'Four'];
const Tab = () => {
const [tabBtn, setTabBtn] = useState('One');
return (
<div className='btnContainer'>
{
buttonList.map(b => {return (
<button
className={b === tabBtn ? 'active' : '' }
key={`${b}Button`}
onClick={() => setTabBtn(b)}
>
{b}
</button>)}
)}
</div>
);
}
export default Tab;
Without map
import React, {useState} from 'react';
const Tab = () => {
const [tabBtn, setTabBtn] = useState('One');
return (
<div className='btnContainer'>
<button
className={'One' === tabBtn ? 'active' : '' }
key={`One Button`}
onClick={() => setTabBtn('One')}
>
One
</button>
<button
className={'Two' === tabBtn ? 'active' : '' }
key={`Two Button`}
onClick={() => setTabBtn('Two')}
>
Two
</button>
</div>
);
}
export default Tab;
Obviously, add in the rest of the buttons up to 7.
I have created a react component that will display movie details after getting details from the TMDb API. The app working perfectly but there is one condition I am trying to handle i.e. when the movie is not found. In that, I case I want my background to be white instead of the movie poster. I want the same thing for title, overview, rating etc. I have used ternary operator for this.
However, my app still crashes this: -
Uncaught TypeError: Cannot read properties of undefined (reading 'backdrop_path')
at HeroArea
Here is my code: -
import React, { useState } from 'react'
import MovieDetailModal from '../MovieDetailsModal/MovieDetailModal';
import './HeroArea.css';
function HeroArea({ movie }) {
const [displayModal, setDisplayModal] = useState(false);
const displayMovieModal = () => setDisplayModal(true);
//Default background if movie.backdrop isn't found
const backdropImage = movie.backdrop_path !== null ?
{ backgroundImage: `url(https://image.tmdb.org/t/p/original/${movie.backdrop_path})` }
: {backgroundColor : "white"};
return (
<>
<MovieDetailModal status={displayModal} movie={movie} setStatus={setDisplayModal} />
<div className="hero-container" style={backdropImage} >
<div className="content-width info-container">
<div className="inner-container">
<h1>{movie.title ? movie.title : "No results found!"}</h1>
<p>{movie.overview ? movie.overview.substring(0, 250) : ""}...</p>
<button
onClick={displayMovieModal}
className="common-button view-more-button-hero">Display more</button>
</div>
</div>
</div>
</>
)
}
export default HeroArea
The short answer is, because movie is undefined, you can't access its properties.
You would need to make sure that movie is set before anything else for example:
const backdropImage = movie.backdrop_path !== null
? { backgroundImage:`url(https://image.tmdb.org/t/p/original/${movie.backdrop_path})` }
: {backgroundColor : "white"};
BECOMES
const backdropImage = movie && movie.backdrop_path !== null
? { backgroundImage:`url(https://image.tmdb.org/t/p/original/${movie.backdrop_path})` }
: {backgroundColor : "white"};
This also means you will need to make sure you only render this component if movie is set. for example:
return (
<>
<MovieDetailModal status={displayModal} movie={movie} setStatus={setDisplayModal} />
<div className="hero-container" style={backdropImage} >
<div className="content-width info-container">
<div className="inner-container">
<h1>{movie.title ? movie.title : "No results found!"}</h1>
<p>{movie.overview ? movie.overview.substring(0, 250) : ""}...</p>
<button
onClick={displayMovieModal}
className="common-button view-more-button-hero">Display more</button>
</div>
</div>
</div>
</>
)
BECOMES
if(movie){
return (
<>
<MovieDetailModal status={displayModal} movie={movie} setStatus={setDisplayModal} />
<div className="hero-container" style={backdropImage} >
<div className="content-width info-container">
<div className="inner-container">
<h1>{movie.title ? movie.title : "No results found!"}</h1>
<p>{movie.overview ? movie.overview.substring(0, 250) : ""}...</p>
<button
onClick={displayMovieModal}
className="common-button view-more-button-hero">Display more</button>
</div>
</div>
</div>
</>
)
}
return null;
I have recreated the radio button behavior in Sandbox.
When one button is active, all the other ones should be inactive.
Please find the link here :
https://codesandbox.io/s/amazing-chaplygin-xf8el?fontsize=14
For 3 buttons I have created 3 functions. Is there a way to optimize my code with 1 single function ?
Thank you
Yes, you can do that by using an Array:
import React, { useState } from "react";
export default function ButtonToggle() {
const [happy, setHappy] = useState([false, false, false]);
function handle(idx) {
let set = [false, false, false];
set[idx] = !happy[idx];
setHappy(set);
}
return (
<div>
{happy[0] ? "😄" : "🤕"}
<button
onClick={() => {
handle(0);
}}
>
bouton1
</button>
{happy[1] ? "😄" : "🤕"}
<button
onClick={() => {
handle(1);
}}
>
bouton2
</button>
{happy[2] ? "😄" : "🤕"}
<button
onClick={() => {
handle(2);
}}
>
bouton3
</button>
</div>
);
}
CodeSandbox: https://codesandbox.io/s/jolly-haibt-73df1
Its difficult for me to understand the errors in this JSX code. It feels like I am applying the correct conventional rules for JSX but below I've posted the feedback that I've received from the console and it seems to stem from the first forEach method inside of the promise.
class EventQueries extends Component{
constructor(props){
super(props);
this.state = {
entertainer: null
}
}
render(){
return(
<div className = 'Immediate_Events'>
<header className = 'ImmEventsTitle'>
Upcoming Events
</header>
<div className = 'EventBlock'>
{return this.props.queryEvent(this.props.query).then(() => this.props.queried_events.forEach(function(event){
return ( <div>
<span className = 'EventTitle'>JSON.parse(event["title"])</span>
{this.props.artist_events ?
this.props.artists_events.forEach((entertainer) => {
return <span className = 'ArtistName'>
<span onClick = {this.state.entertainer !== entertainer.name ? this.props.ParseEventsByArtist(entertainer.name, this.props.eventForecast).then(function(){this.setState({artist: entertainer.name})}) : null}>
entertainer.name
</span>
</span>}) :
event.performers.forEach((entertainer) => { return <span className = 'ArtistName'>
<span onClick = {this.state.entertainer !== entertainer.name ? this.props.ParseEventsByArtist(entertainer.name, this.props.eventForecast).then(function(){this.setState({artist: entertainer.name})}) : null}>
entertainer.name
</span>
</span>
})
}
<span className = 'EventHappenstance'>JSON.parse(event["venue"]["name"])</span>
<span className = 'EventAddress'>JSON.parse(event["venue"]["address"]), JSON.parse(event["venue"]["extended_address"])</span>
</div>
)
}))
}
</div>
</div>
)
}
function mapStateToProps(state){
queried_events: state.eventOptions.queried_events
}
export default connect(mapStateToProps, {queryEvent})(EventQueries)
In the browser console, this is what I am getting in return for this particular file: EventQueries.js
Any help would be appreciated. Thanks.
This was a simple mistake. I simply needed to add a return in front of queried_events in the mapStateToProps in order for the function to understand what the this.props.queried_events was referring to.
You need to remove the return statement from here:
<div className = 'EventBlock'>
{return
You're essentially nesting a return inside a return. It's not necessary there.