I'm building a wordpress block using react (in the frontend).
The block will initially fetch a list from a server, then display the list using map.
For each item, it will render a header, like so:
As you can see, you can click a header and the content shows up. This content is build in the same map and they have their max-height and opacity set to 0 to hide them. I'm using those properties instead of just display: none, because I can CSS-transition them and it looks smoother. I had to blur the content, but you get the idea.
However, in some of the content-divs, the buttons are not working. The links-stlyed-as-buttons (the music services on the left) do not behave as links, although they have their href set in the markup. The hover effects do not work either, the cursor does not become the pointy finger and they are not clickable.
A div styled as a play-button has the same issues: in eventListeners I can see the onClick being listened for, but the button is not clickable, has no hover, etc.
One noteable thing is: it's not all list entries behaving this way. And if one list entry with broken buttons is open, and you open another content section with working buttons, the broken buttons will magically start working. If you then close the content section with working buttons, the formerly broken ones are broken again.
Honestly, this feels like my code is haunted.
Please note: because the length and content of the list is not entirely known, I have to use generated IDs and generated getElementByID-queries to interact with the items and can't define states for them (at least I couldn't think of a way to dynamically create states).
React:
//...
//releases is useState([]) of an object with metadata of songs
//comes from a database query, so the columns are known
{releases.map(release => {return(
<div key={release.catalogue_index} style={{marginTop: "8px"}}>
{/*This is the "header", shown in the screenshot*/}
<div className="layout-row" style={{backgroundColor: "#111", padding: "8px", marginTop: "4px", position: "relative"}} onClick={(event) => {
document.getElementById(`${release.catalogue_index}-content`).classList.toggle('open');
}}>
<div stlye={{flexGrow: 1}} className="layout-stack">
{/* here the title and some information is displayed*/}
</div>
</div>
{/*The content you can show (second screenshot)*/}
<div className="release-content" id={`${release.catalogue_index}-content`}>
{/*layout-stack and layout-row are just flex containers with different directions*/}
<div className="layout-row">
<img loading="lazy" alt={`${release.title} cover`} src={/*cover.jpg*/}
className="release-cover" />
<div className="layout-stack">
<div>{/*some metadata*/}</div>
<hr />
{release.short_description}
<div style={{height: "16px"}} />
<div className="layout-row">
{/*those are the link buttons sometimes not working*/}
{/*the whole thing only gets displayed if any link got fetched from the database*/}
{(release.link_bandcamp || release.link_youtube || release.link_spotify || release.link_apple) ?
<div className="layout-row">
<p className="link-caret"><strong>></strong></p>
<ul className="is-content-justification-center is-layout-flex wp-container-9 wp-block-social-links has-icon-color has-icon-background-color featured-social-group" style={{margin: 0}}>
{release.link_bandcamp ?
<li style={{color: "#fff", backgroundColor: "#888"}} className="wp-social-link wp-social-link-bandcamp wp-block-social-link wp-custom-social">
<a target="_blank" href={release.link_bandcamp} className="wp-block-social-link-anchor" rel="noopener"><img className="svgbutton" src={/*some-logo.svg*/} />
<span className="wp-block-social-link-label screen-reader-text">Bandcamp</span></a></li>
: null}
{release.link_youtube ?
<li style={{color: "#fff", backgroundColor: "#888"}} className="wp-social-link wp-social-link-youtube wp-block-social-link wp-custom-social">
<a target="_blank" href={release.link_youtube} className="wp-block-social-link-anchor" rel="noopener"><img className="svgbutton" src={/*some-logo.svg*/} />
<span className="wp-block-social-link-label screen-reader-text">Youtube</span></a></li>
: null}
{release.link_spotify ?
<li style={{color: "#fff", backgroundColor: "#888"}} className="wp-social-link wp-social-link-spotify wp-block-social-link wp-custom-social">
<a target="_blank" href={release.link_spotify} className="wp-block-social-link-anchor" rel="noopener"><img className="svgbutton" src={/*some-logo.svg*/} />
<span className="wp-block-social-link-label screen-reader-text">Spotify</span></a></li>
: null}
{release.link_apple ?
<li style={{color: "#fff", backgroundColor: "#888"}} className="wp-social-link wp-social-link-chain wp-block-social-link wp-custom-social">
<a target="_blank" href={release.link_apple} className="wp-block-social-link-anchor" rel="noopener"><img className="svgbutton" src={/*some-logo.svg*/} />
<span className="wp-block-social-link-label screen-reader-text">Apple Music</span></a></li>
: null}
</ul>
</div> : null}
<audio id={`audio-${release.catalogue_index}`} preload="none"
onEnded={() => {document.getElementById(`audio-seek-${release.catalogue_index}`).value = 0}}
onLoadedMetadata={() => document.getElementById(`audio-seek-${release.catalogue_index}`).max = document.getElementById(`audio-${release.catalogue_index}`).duration}
onTimeUpdate={() => document.getElementById(`audio-seek-${release.catalogue_index}`).value = Math.floor(document.getElementById(`audio-${release.catalogue_index}`).currentTime)}>
<source src={/*REDACTED*/} type="audio/mpeg" />
Your browser does not support audio.
</audio>
<div className="layout-row" style={{alignItems: "center"}}>
{/*this is the play button sometimes acting up*/}
<div className="play-pause wp-block-button"
onClick={() => {togglePlayPause(release.catalogue_index)}}>
<img id={`audio-button-${release.catalogue_index}`} className="play-pause svgbutton wp-block-button__link wp-element-button" src={/*play-svg*/} />
</div>
<input type="range" id={`audio-seek-${release.catalogue_index}`} className="audio-seek" max={100} value={0} />
</div>
</div>
</div>
</div>
<div style={{height: "16px"}} />
<div className="layout-stack">
{/*some flavor text*/}
</div>
</div>
</div>
)})}
CSS:
//...
.release-content {
max-height: 0vh;
opacity: 0;
transition: max-height 0.3s;
transition: opacity 0.3s;
}
.release-content.open {
opacity: 1;
height: fit-content;
padding: 16px;
max-height: 100vh;
}
.svgbutton {
color: currentColor;
fill: currentColor;
width: 1em;
height: 1em;
}
div.play-pause {
margin-left: 36px !important;
height: 38px;
}
img.play-pause {
box-sizing: unset !important;
margin-top: 0 !important;
}
//...
The only thing I could think of was that maybe the wordpress-classes ("wp-...") would somehow break ... but that doesn't make much sense, as some of the the list entries work fine while others don't - all using those same classes.
Based on RubenSmn's comment, I had to realize that I did not plan my code well and built terrible anti-patterns.
I have refactored the code to not map into all that markup, but a separate <Release /> component, which in turn contains the markup.
{releases.map(release => {return(
<ReleaseComponent key={release.catalogue_index} release={release} />
)})}
The new component was then built to not use classList.toggle, but proper React states to show and hide the content panels. Also the document.getElementByID-queries are gone and replaced by proper React refs.
const ReleaseComponent = (props) => {
const contentDiv = useRef(null);
const audioElement = useRef(null);
const audioButton = useRef(null);
const audioSeek = useRef(null);
const [contentOpen, setContentOpen] = useState(false);
//...
return(
//...
<div className="release-content" ref={contentDiv} hidden={!contentOpen}>
//...
Turns out, if you do things right, they actually work... This was a pretty humbling experience. Thank you, #RubenSmn .
Related
I want my sidenavbar to continue over the whole page but when i add the other
sections(home, contact & projects) which are just regular functional components
with a div and h1, they create their own space on the page. is there a better
solution to creating different sections on a page? i have tried rendering the components
from index and app.js but without success, i am currently rendering SidenavBar
from index.js and my sections are getting rendered from app.js.
import React from "react";
import "../Section.css";
function HomeSection() {
return (
<div className="Section" id="Home">
HomeSection
<h1>Home</h1>
</div>
);
}
export default HomeSection;
here is an example of the sections, the section.css only centers the text on the page.
function SideNavBar() {
const [titleActive, setTitleActive] = useState(HomeSection);
return (
<div className="SideNavBar">
<Stickybox>
<ul className="SideBarList">
{SideBarInfo.map((info, key) => {
return (
<li
key={key}
className="rad"
onClick={() => {
console.log(info.title + " clicked");
setTitleActive(info.title);
}}
id={titleActive === info.title ? "active" : ""}
>
<Link
onClick={() => {
console.log(info.title + " clicked");
setTitleActive(info.title);
}}
id={titleActive === info.title ? "active" : ""}
activeClass="active"
to={info.title}
spy={true}
smooth={true}
offset={50}
duration={500}
>
<div id="title">{info.title}</div>
/Link>
<Link
activeClass="active"
to={info.title}
spy={true}
smooth={true}
offset={50}
duration={500}
>
<div id="bild">{info.bild}</div>
</Link>
</li>
);
})}
</ul>
</Stickybox>
</div>
);
}
export default SideNavBar;
// this is the css for sidebar
.SideNavBar {
width: 250px;
min-height: 5000px;
background-color: rgb(47, 167, 223);
height: 100vh;
}
this is my sidenavbar component.
My sidenavbar works as intended if i remove the sections, i have tried setting a max width and transparent background for the sections so they dont overwrite the sidenavbar but they still overwrite it. what is the correct way to create different sections?
i added a red background for the home section so its easier to see what its doing.
You probably want to do something like this for your sidebar to fix it on the side and have it take up the full screen.
This will fix the sidebar in a position on the screen (0px away from the top and 0px away from the bottom).
You then define the width and you have a fixed sidebar!
Hope that helps!
.sidebar {
top: 0px;
bottom: 0px;
width: 200px;
position: fixed;
background-color: blue;
}
<div class='sidebar'></div>
In React application I am displaying list of images. When individual book is removed Hide Books button takes the place to that component.
What I am trying to achieve is Hide Books button should remain at the same position and should dynamatically change its position on y axis if whole row of books is deleted
Initial state of application
When individual book is removed -
app.js
return(
<div style={{ position: "relative", minHeight: "100vh" }}>
<button
style={{
position: "absolute",
bottom: "",
}}
onClick={clearBooks}
>
Hide Books
</button>
</div>
)
could you share more of your code? maybe have a codesandox example? It seems to be a styling issue but it's hard to tell without more code.
-edit-
your button should be separated from your list of books, this is the reason why it essentially "follows" your last book card.
Try to do something like this
return (
<section className='wrapper'>
<div className='bookList'>
{booksData.map(book => {
//code your books here
}
</div>
//then put your button out of the div
<button onClick={function}>hide books</button>
</section>
)
your CSS for the wrapper div could be something like this
.wrapper{
display: flex;
flex-direction: column
}
this way you'll have the books first then the button will be displayed below the list
Place the button as the next sibling to the section of Books. Shown in the following. All I did was to move the button out of the section. You will have to style the button with padding and such for the updated layout.
// in index.js, BookList
return (
<>
<section className="booklist">
{booksData.map((book, index) => {
return (
<Book
key={index}
{...book}
removeIndividualBook={removeIndividualBook}
></Book>
);
})}
</section>
{booksData.length === 0 ? (
<button onClick={handleShowBook}>Show Books</button>
) : (
<div style={{ position: "relative", minHeight: "100vh" }}>
<button
style={{
// position: "absolute",
// marginTop: "2350px",
// marginLeft: "28px",
position: "absolute",
//left: "12%",
bottom: "",
}}
onClick={clearBooks}
>
Hide Books
</button>
</div>
)}
</>
);
I want to create something such that, depending on the state, a given div appears overlapping another div from the right side, here is my code:
const [loggedIn, setLoggedIn] = useState<boolean>(false);
const [hasConfirmedAccount, setHasConfirmedAccount] = useState<boolean>(false);
return (
<>
<div style={{ width: "100%" }}>
<div style={{ float: "left", width: "50%" }}>
<div
style={{ width: "100%", height: "100vh", backgroundColor: "#fafafafa" }}
></div>
</div>
<div id='notLoggedIn' style={{ float: "right", width: "50%" }}>
{!loggedIn && (
<div>
WHEN LOGGED IN === TRUE
</div>
)}
<div
style={
loggedIn && !hasConfirmedAccount
? { width: "100%", transition: "ease-in-out 5s" }
: { display: "none" }
}
>
<div id="notConfirmedAccount">WHENE LOGGED IN === TRUE AND hasConfirmedAccount === FALSE</div>
</div>
</div>
</div>
</>
);
The code works fine, when loggedIn === true and hasConfirmedAccount === false div with id = notConfirmedAccount has been displayed instead of div with id=notLoggedIn, but displaying this div does not work flowing, I want a slow leaving effect of the div on the right side that would overlap the previous div
can someone tell me what to do this?
thanks for any help!
install animate.css => $ npm install animate.css --save
animate.css
2.import "./animate.css" at top your component or project
3.just put the name of aniamte on className like this pattern in your div
<div className={style.forgot} className='animate__animated animate__fadeInDown'>
also you should control your showing div with state
Use React animation Add-Ons ReactTransitionGroup and ReactCSSTransitionGroup
The ReactTransitionGroup add-on component is a low-level API for animation, and ReactCSSTransitionGroup is an add-on component for easily implementing basic CSS animations and transitions.
https://reactjs.org/docs/animation.html
Using react-particles-js
as a background on a React project, I discover that disables the anchor tag, don't know if its my implementation
const App = () => {
return (
<div className="App" style={{ position: "relative", overflow: "hidden" }}>
<div style={{ position: "absolute" }}>
<Particles height="330vh" width="100vw" params={particlesConfig} />
</div>
<Home /> {/*this is the content */}
</div>
);
};
What it happens its that in this component with link like this
<a
href="https://tienda-de-garage.herokuapp.com/"
style={{ textDecoration: "none", color: "black" }}
>
<p>Tienda de Garage</p>
</a>
Don't work.
I wonder if its the implementation, maybe the use of the view port the increase the size of the area to encompass the background but i'm not sure.
here its a live version, with the 1 link not working to show the issue
You need to set interactivity.detectsOn to window (InteractivityDetect.window or "window")
You can see a working sample here
This sample uses react-tsparticles but it's the same as react-particles-js since they share the same core library tsparticles
Currently I'm using react.js and I'm trying to get two div's to be side by side.
Currently I'm trying to
<div id="sidebar" style = "display:inline-block;" >
<script src="build/sidebar.js"></script>
</div>
<div id="map-canvas" style="display: inline-block; width: 20%; height: 50%; "></div>
with sidebar.js as the where react is stored. This unfortunately doesnt work however as it just moves map-canvas to the side while sidebar isn't to the left of it; its on top. I've tried many various combinations w/ float as well and none of them seem to work
Another option is to edit the sidebar.js code where I currently have
return <div>
<input type="text" value={this.state.searchString} onChange={this.handleChange} placeholder="Type here" />
<ul>
{ libraries.map(function(l){
return <li>{l.name} </li>
}) }
</ul>
</div>;
in which I try doing return <div style ="display: inline-block;">
However, in this case the generated html doesnt show up at all. I'm perplex to what I should try but react seems like it doesnt want to play nice with other div elements.
That's because in React, the style prop takes an object instead of a semicolon-separated string.
<div id="sidebar" style={{display : 'inline-block'}} >
<script src="build/sidebar.js"></script>
</div>
<div id="map-canvas" style={{display: 'inline-block', width: '20%', height: '50%'}}>
</div>
Edit:
So this:
return <div style="display: inline-block;">
Would become this:
return <div style={{display: 'inline-block'}}>
const styles = {
container: {
backgroundColor: '#ff9900',
...
...
textAlign: 'center'
}
}
export default class App extends React.Component {
render() {
return(
<div className="container" style={styles.container}>
// your other codes here...
</div>
);
}
}