React Media Query needs refresh to show image - javascript

I am using react-media (https://github.com/ReactTraining/react-media) to handle different screen sizes. The aim of using react-media: Just bigger screens should see the parallax image (using materializeCSS for parallax). Problem:
If you resize the window, the image will disappear (how it should be) and when you go back to the bigger screen the place of the image is white. After refreshing the page the image is there again. I noticed it occurs every time when I use media and a javascript materializeCSS "package". How can I fix that?
import React, { useLayoutEffect } from "react";
import picture from "../../image/Introduction.jpeg";
import Media from "react-media";
const Paralaxes = () => {
useLayoutEffect(() => {
const M = window.M;
const elems = document.querySelectorAll(".parallax");
M.Parallax.init(elems, {});
});
return (
<Media query={{ minWidth: 768 }}>
{matches =>
matches ? (
<div className="parallax-container">
<div className="parallax">
<img src={picture} className="responsive-img" alt="background" />
</div>
</div>
) : (
<div className="container">
<div className="divider black" />
</div>
)
}
</Media>
);
};
export default Paralaxes;
Thanks a lot!

Related

How to use a state as the height for a div in React?

I have been working on a project which requires the user to input the height and width through which a div would be displayed of the provided dimensions.
The state is being updated but the height of the div is not changing.
import { useState } from "react"
import './App.css'
function App() {
const [height, setHeight] = useState(0)
const handleInput = e => {
setHeight(e.target.value)
}
return (
<div className="App">
<h1>Sheet Cutter</h1>
<input type="number" placeholder="Height" onChange={handleInput} value={height}/>
<div className="sheet" style={{height: {val}}}>
</div>
</div>
)
}
export default App
I tried another method in which I used increments to update the height and that was working but that way is not practical
I can see 2 errors in the code fragment that you shared.
val is not defined anywhere. You should be using the state height instead of an undefined variable.
You are not adding px at the end.
<div className="sheet" style={{height: `${height}px`}}>
</div>

ReactJS frustrating element.scrollTop bug

I have this frustrating problem with scroll in my ReactJS and TailwindCSS project. I was trying to show element when viewport is on specific part of my website and to hide it when it's not.
function App() {
const scrollRef = createRef()
const [isVisible, setIsVisible] = useState(false);
const handleScroll = () => {
let heightToShow = 1000;
const winScroll = document.querySelector('.App').scrollTop;
if (winScroll > heightToShow) {
setIsVisible(true);
} else {
setIsVisible(false);
}
};
return (
<div onScroll={handleScroll} className="App scroll-smooth relative bg-secondary h-screen snap-y snap-mandatory overflow-x-hidden overflow-y-scroll flex flex-col">
<div ref={scrollRef} />
<Header />
<About />
<Skills />
<Projects />
<Contacts />
<TopButton isVisible={isVisible} ref={scrollRef} />
</div>
);
}
export default App;
At first, i've tried using window.pageYOffset which didn't work, because the value always stayed at 0 and element didn't show up. With document.querySelector('.App').scrollTop I made the functionality work as needed, but I got this terrible bug, where if winScroll's value gets to heightToShow's value - my viewport jumps back to the original winScroll's value. So basically, It is almost impossible to scroll both ways with mousewheel past my heightToShow value.
Any thoughts on why it is happening?

React Accordion Update height when child DOM has new Table to render

In the image as you can see, I have a Foo page, where I have 10 Accordions, In one of the Accordions there is a Form component, When I submit the Form it calls a remote API and returns some JSON data, I convert it to a Table of content and want to show it under the Form.
The problem is I can show the Table after toggling the Accordion again after the submit button clicked, as I have set the maxheight in the onClick.
const [activeState, setActiveState] = useState("");
const [activeHeight, setActiveHeight] = useState("0px");
const toogleActive = () => {
setActiveState(activeState === "" ? "active" : "");
setActiveHeight(activeState === "active" ? "0px" :`${contentRef.current.scrollHeight}px`)
}
return (
<div className={styles.accordion_section}>
<button className={styles.accordion} onClick={toogleActive}>
<p className={styles.accordion_title}>{title}</p>
</button>
<div ref={contentRef}
style={{ maxHeight: `${activeHeight}` }}
className={styles.accordion_content}>
<div>
{content}
</div>
</div>
</div>
)
I have used context also to share the useState hook between Accordion and Form components to update the height.
<UpdateHeightContext.Provider value={{updateHeight, setUpdateHeight}}>
<Accordion title="Find your Data" content={< FormWithTwoInput firstLabel="FirstName" secondLabel="LastName" buttonColor="blue" buttonText="Check Deatils"/>} />
</UpdateHeightContext.Provider>
Is there any way to update the Accordions height dynamically when I receive the response from the API? Other than toggling it again. A similar question was asked here React accordion, set dynamic height when DOM's children change unfortunately no one replied.
Even though the working around what I have found is not a robust one, but it is working completely fine for me. If someone stumbles upon this same issue might find this useful.
import React, { useState, useRef } from 'react'
const Accordion = ({ title, content }) => {
const [activeState, setActiveState] = useState("");
const [activeHeight, setActiveHeight] = useState("0px");
const contentRef = useRef("form")
const toogleActive = () => {
setActiveState(activeState === "" ? "active" : "");
setActiveHeight(activeState === "active" ? "0px" :`${contentRef.current.scrollHeight + 100}px`)
}
return (
<div className={styles.accordion_section}>
<button className={styles.accordion} onClick={toogleActive}>
<p className={styles.accordion_title}>{title}</p>
</button>
<div ref={contentRef}
style={{ maxHeight: `${activeHeight}` }}
className={styles.accordion_content}>
<div>
{content}
</div>
</div>
</div>
)
}
Accordion.propTypes = {
title: PropTypes.string,
content: PropTypes.object,
}
export default Accordion
I have hardcoded some extra space so that while the dynamic response is accepted the Table content is shown. In the CSS module file, I have kept the overflow as auto, earlier it was hidden.
.accordion_content {
background-color: white;
overflow: auto;
max-height: max-content;
}
As a result, the Table is appearing dynamically and the user can scroll inside the Accordion if my Table needs larger space.

React: Making width of div equal to height. The height is not being calculated correctly

Github repo of this project
Based on other solutions that I have seen to this problem, I've created a component that is supposed to calculate the width and height of it's children, and then set the width and the height to be equal to the length of whichever one is longer.
Ex. If the width=30 and the height=20, the width and height should be set to 30. The result should be the same if the height is 30 and the width is 20.
import React, {useState, useEffect, useRef} from 'react';
const SymmetricalDiv = ({style, children, ...props}) => {
const [diamStyle, setDiamStyle] = useState({});
const elementRef = useRef(null);
style = style ? Object.assign({}, diamStyle, style) : diamStyle ;
useEffect(() => {
const width = elementRef.current.clientWidth;
const height = elementRef.current.clientHeight;
const diam = Math.max(width, height);
setDiamStyle({width: diam, height: diam});
}, []);
return (
<div ref={elementRef} {...props} style={style}>
{children}
</div>
);
};
Here's an example where I try to use this component. (The styling is done using bootstap)
import React from 'react';
import {SymmetricalDiv} from 'components/Styled'
import svgLogo from 'src/SVG_logo.svg'
const MyComponent = () => {
return (
<SymmetricalDiv className='rounded-circle d-flex flex-column align-items-center bg-danger'>
<strong >A title</strong>
<span>A description</span>
<img className='my-3' src={svgLogo} />
A Link
</SymmetricalDiv>
);
};
This example is producing the following result. It's calculating the height incorrectly, and deciding that the width is the longer dimension. Then it's setting the width and the height to be equal to the width, which is why some of the children appear outside the circle.
The reason it doesn't match the height/width appears to be because your image doesn't have a set height/width.
Images without set heights/widths initially start out with 0 width/height, this is where your calculation happens. The image then loads and a reflow happens.
There's two easy ways to fix your issue:
Set the width for the image
This makes sure the image knows its height/width before it's fully loaded.
<SymmetricalDiv className="rounded-circle d-flex flex-column align-items-center bg-danger">
<strong>A title</strong>
<span>A description</span>
<img className="my-3" width="168px" height="150px" src={svgLogo} />
A Link
</SymmetricalDiv>
Inline the SVG/Make it a component
This removes the load step of the image altogether.
// SVGLogo.js
export default () => {
return <svg>...</svg>
}
// App.js
<SymmetricalDiv className="rounded-circle d-flex flex-column align-items-center bg-warning">
<strong>A title</strong>
<span>A description</span>
<SVGLogo />
A Link
</SymmetricalDiv>
You can see both implementations in action in this Code Sandbox example
Being explicit about the sizes of images can be really helpful for ensuring your app behaves as expected.
You can also read more about preventing reflow due to image loading

Animate on scroll using react.js

I am using some css animations from animate.css and I'm using react.js which works fine at the top of my page however, I also have some animations near the middle of the page. When my page loads everything animates at once which means once I scroll down the animations in the middle of the page have already completed. I am looking for away to delay the animations until that area of the screen is visible. I have found some questions/answers on here but they date back quite a few years and appear to be outdated.
As seen in the code below the animate__animated animate__bounce animate__zoomInDown classes are derived from animate.css but play immediately when the page is loaded and not when visible onscreen:
import React from "react";
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faHourglassStart} from '#fortawesome/free-solid-svg-icons'
function MiddleContainer() {
return (
<div>
<div id = "middle-container" class="middle-container">
<h1>What can I offer you?</h1>
<div className = "fast animate__animated animate__bounce animate__zoomInDown">
<FontAwesomeIcon className="social-icon" icon={faHourglassStart} size = '4x' color = "black"/>
<h4>Fast and Reliable Service</h4>
<p>Your product will be delivered to you with precision, care and in a timely manner.</p>
<p>Add more info here when you are done with the css. </p>
</div>
</div>
</div>
)
}
export default MiddleContainer;
So I was able to solve this myself using a different library as I couldn't find any documentation from animate.css on how to animate on scroll
The new library with documentation that worked is AOS from https://michalsnik.github.io/aos/
I had to use useEffect from react.js in order for it to work.
Here is my code with animate on scroll working:
import React, { useEffect } from "react";
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faHourglassStart} from '#fortawesome/free-solid-svg-icons'
import AOS from "aos";
import "aos/dist/aos.css";
function MiddleContainer() {
useEffect(() => {
AOS.init({
// duration : 5000
});
}, []);
return (
<div>
<div id = "middle-container" class="middle-container">
<h1>What can I offer you?</h1>
<div className = "fast" data-aos="zoom-in">
<FontAwesomeIcon className="social-icon" icon={faHourglassStart} size = '4x'
color = "black"/>
<h4>Fast and Reliable Service</h4>
<p>Your product will be delivered to you with precision, care and in a
timely manner.</p>
<p>Add more info here when you are done with the css. </p>
</div>
</div>
</div>
)
}
export default MiddleContainer;

Categories