How to React js event on scroll load other components - javascript

I have more components in one page. All pages loaded at the same time.
But i want after scroll event loading next componentas.
HomePage.js:
render() {
return (
<section className="section1">
<Component1 />
</section> <section className="section2">
<Component2 />
</section>
<section className="section3">
<Component3 />
</section>
<section className="section4">
<Component4 />
</section>
<section className="section5">
<Component5 />
</section>
<footer>
<Footer />
</footer>
);
}
Have any idea? It is possible in react.
Thank you!

You'll need to listen to a scroll event -- something like this:
componentDidMount() {
window.addEventListener('scroll', this.handleScroll)
}
Keep in mind that you may want to listen to a scroll event on a specific element, and not the entire window. This will depend on your requirements for how/when these other components should load.
In handling that event, keep track of your scroll distance somehow.
handleScroll = (event) => {
this.setState({
scrollY: window.scrollY
});
}
Note: Updating your state on every scroll event is probably over-kill though. I think the best approach would be to detect when the user has scrolled to the bottom and then conditionally load/render new components.
Then, in your render function, conditionally render additional components based on the value of your scroll distance. Again, you will likely need to include more sophisticated logic here based on your specific needs, but here is a rudimentary example based on scroll distance:
render() {
let additionalComponents = null;
if (this.state.scrollY > 1000) { //arbitrary amount
additionalComponents = (
<Component6 />
);
}
return (
<section className="section1">
<Component1 />
</section> <section className="section2">
<Component2 />
</section>
<section className="section3">
<Component3 />
</section>
<section className="section4">
<Component4 />
</section>
<section className="section5">
<Component5 />
</section>
{ additionalComponents }
<footer>
<Footer />
</footer>
);
}

Related

Javascript attribute - onClick and onClickOverThere for dropDown

I have reactJs app and I have made a custom dropDown with a div that I set an onClick attribute to open dropDown and close it.
but also I want to close it when the user clicks to another part of the site.
<div
onClick={() => setNoneQuote(noneQuote ? false : true)}
className="selected-drop-down"
>
<span className="dropDownText">{selectedQuoteCurrency}</span>
<img
className="dropDownIcon"
src={require("../assets/image/arrow/dropDown-Arrow.png")}
width="15px"
alt="arrow"
/>
</div>
I try onMouseDown instead of onClick according to this answer ==> stackoverflow ,but I don't know why it doesn't work for me :(
const dropdownElement= document.querySelector("choose an id or a specific class")
window.onclick = function(event) {
if (event.target !== dropdownElement) {
dropdownElement.style.display = "none"; // or any other function that you want to call
}
}
this may not be the exact code to fix your problem but you can use the logic
You could do it in different ways, but I will show you solution that I used in one of my projects.
So, I used <header> and <main> tags where I had all my Components. And in those tags i used eventListener with a callback function, like this:
<header onClick={handleClick}>
<Nav />
<Greeting />
<Sidebar />
</header>
and
<main onClick={handleClick}>
<Description />
<Icons />
<Prices />
<Gallery />
<NecessaryInfo />
<Location />
<GalleryModal />
<ConditionsModal />
</main>
In a callback function handleClick I checked where user could click and to do that I used next logic of pure JS:
!e.target.classList.contains("menu-open") &&
!e.target.classList.contains("menu-links") &&
!e.target.parentElement.classList.contains("menu-links") &&
!e.target.parentElement.parentElement.classList.contains("menu-links") &&
closeSidebar();
Function closeSidebar() is simple:
const closeSidebar = () => {
setIsSidebarOpen(false)};
In your code instead of using setNoneQuote(noneQuote ? false : true) you could also use: setNoneQuote(!noneQuote). Exclamation mark before value always will change it to the oposite.

How to render a component outside the component that contains the function that renders the first component?

The situation is a bit complicated:
inside a component called "LeftSectionHeader" I have a div, which when clicked must render a component;
the component to be rendered is called "ProfileMenu", and is basically a div that must be rendered on top of "LeftSectionHeader" itself and another div;
All these components are rendered inside another component called "Main".
The problem is that if I define the function inside "LeftSectionHeader", "ProfileMenu" will be rendered inside, while I need it to not only be rendered outside, but even cover it; that's why you'll see some boolean vars inside "Main", because that is the only way i could render it, but it still doesn't cover the other divs. I'll attach the code of each component and how the final result should look below.
LeftSctionHeader:
function LeftSectionHeader(){
return(
<div class="left-section-header">
<div class="crop" ><img src="./images/profiles/anonimous.png" /></div>
</div>
);
}
The div belonging to the "crop" class is the one that must be clicked to render "ProfileMenu"
ProfileMenu:
function ProfileMenu(){
return(
<div class="profile-side-menu">
//A lot of boring stuff
</div>
);
}
There are some functions related to this component, but they are not important, so I didn't put them, just ignore it
Main:
var p=true;
var m=true;
function Main(){
return(
<div class="main">
<Header />
<div class="left-section">
{m ? <div><LeftSectionHeader /><LangMenu /></div> : <ProfileMenu />}
</div>
{p ? <PostPage /> : <NoPostsMessage />} //Ignore this line
</div>
);
}
Before clicking on the orange div
After clicking
This might help as guidline, hopefully!
function LeftSectionHeader({ onClick }){
return(
<div class="left-section-header" onClick={onClick}>
<div class="crop" ><img src="./images/profiles/anonimous.png" /></div>
</div>
);
}
function Main(){
const [showProfile, setShowProfile] = useState(false);
return(
<div class="main">
<Header />
<div class="left-section">
{!showProfile ? (
<div>
<LeftSectionHeader onClick={() => setShowProfile(true)} />
<LangMenu />
</div>
) : <ProfileMenu />}
</div>
{p ? <PostPage /> : <NoPostsMessage />} //Ignore this line
</div>
);
}
The simplest solution might be to pass a handler into the header component to toggle the menu:
function App () {
const [showMenu, setShowMenu] = useState();
return (
<div>
<Header onMenuToggle={() => setShowMenu(!showMenu)} />
{ showMenu && <Menu /> }
</div>
)
}
function Header ({ onMenuToggle }) {
<div onClick={onMenuToggle}>...</div>
}
Caveat: This will cause the entire App component to re-render when the menu state changes. You can mitigate this by either
A) placing the menu state closer to where it's actually needed, like in the sidebar component instead of at the top, or
B) using a context or other orthogonal state store.
Another approach would be to leave the state handling in the LeftSectionHeader component and then use a React portal to render the menu elsewhere in the DOM.

Scroll to Top of Page onClick with React

I have a component that is rendered with a static ID called #mainView. I have a component that renders a button element lower in the page, and I want to scroll up to the #mainView element when the button is clicked. As far as I can tell, this is a very simple user experience that has been apart of the web standard for decades now and can be accomplished with a simple ... in vanilla HTML (and extended with scroll-behavior: smooth as an experimental feature).
I have spent the last hour trying to replicate this behavior in React, to no avail. Hashes in URLs are ignored, and Gatsby complains about an external link. I have tried #reach/router/navigate and Link. I have tried to use onClick={...}, and manually trying to override onclick does not work. None of these produce any behavior at all and the only approaches I can find on SO involve extending React.Component and getting inside render(), using another method, using refs, and all sorts of stuff that should 10,000% not be necessary for such simple UX.
Is there any way to get React to easily replicate what I want here? And, why might the React developers actively break traditional web functionality? All responses appreciated.
Probably not the beautiful way to do it, but you can try using element.scrollIntoView, in the example I'm using the id and document.getElementById but you can replace it with ref
const Element = ({id,text})=>(<div id={id} style={{width:"100%", height: "400px", border:"solid 1px black"}} >{text}</div>);
const Scroll = ({to})=><span onClick={()=>document.getElementById(to).scrollIntoView({behavior:"smooth"})} >Scroll</span>
const App = ()=><div>
<h1>MyApp</h1>
<Element id="el-1" text="Lorem Ipsum" />
<Element id="el-2" text="Lorem Ipsum" />
<Element id="el-3" text="Lorem Ipsum" />
<Scroll to="el-2"/>
</div>
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
And yes, if it's not to a element, but to the top window.scrollTo({top:0,behavior:'smooth'}) should be enough.
I was using Gatsby, and the solution was to import gatsby-plugin-smoothscroll package and add to plugins (docs), then navigate with:
<button onClick={() => scrollTo('#mainView')}>My link</button>
class Scroll extends React.Component {
constructor(props) {
super(props);
this.myRef1 = React.createRef();
this.myRef2 = React.createRef();
this.myRef3 = React.createRef();
this.myRef4 = React.createRef();
}
scrollSmooth(e, scroll) {
if (scroll === "sec1") {
this.myRef1.current.scrollIntoView({
behavior: "smooth",
block: "start"
});
} else if (scroll === "sec2") {
this.myRef2.current.scrollIntoView({
behavior: "smooth",
block: "start"
});
} else if (scroll === "sec3") {
this.myRef3.current.scrollIntoView({
behavior: "smooth",
block: "start"
});
} else if (scroll === "sec4") {
this.myRef4.current.scrollIntoView({
behavior: "smooth",
block: "start"
});
}
}
render() {
return (
<div className="container">
<ul className="list-group">
<li className="list" onClick={e => this.scrollSmooth(e, "sec1")}>
section1
</li>
<li className="list" onClick={e => this.scrollSmooth(e, "sec2")}>
section2
</li>
<li className="list" onClick={e => this.scrollSmooth(e, "sec3")}>
section3
</li>
<li className="list" onClick={e => this.scrollSmooth(e, "sec4")}>
section4
</li>
</ul>
<div className="row">
<div className="section1" ref={this.myRef1}>
<p>Section 1</p>
</div>
<div className="section2" ref={this.myRef2}>
<p>Section 2</p>
</div>
<div className="section3" ref={this.myRef3}>
<p>Section 3</p>
</div>
<div className="section4" ref={this.myRef4}>
<p>Section 4</p>
</div>
</div>
</div>
);
}
}
export default Scroll;
Hi refer this component.
Working link click here

React - Navigation that will smooth scroll to section of the page

So I'm trying to create a navigation for my single page app that will smooth scroll down to the section of the page.
I want to have my navigation at the top of the page with links that when a user clicks, will smooth scroll them down to the section of the page. I'd also like it so if the user goes directly to the link website.com/about for example, it will smooth scroll to the section the same way as if you clicked about on the navigation component.
I understand how the react-router-dom works for routing pages, but I'm confused on how to make it work for this particular purpose.
Could this be achieved with HashRouter?
Here's the code I currently have:
function Header() {
return (
<>
<Link to="/">Hero</Link>
<Link to="/">About</Link>
<Link to="/">Contact</Link>
</>
);
}
function Hero() {
return (
<section>
<h1>Hero Section</h1>
</section>
);
}
function About() {
return (
<section>
<h1>About Section</h1>
</section>
);
}
function Contact() {
return (
<section>
<h1>Contact Section</h1>
</section>
);
}
export default function App() {
return (
<div className="App">
<BrowserRouter>
<Header />
<Hero />
<About />
<Contact />
</BrowserRouter>
</div>
);
}
I'm also providing a CodeSandBox, forks are appretiated! :)
What you could do is use an anchor tag instead of Link from react-router-dom and have an id on the sections. when the anchor tag is clicked scroll to the corresponding section
<a
href="/"
onClick={e => {
let hero = document.getElementById("hero");
e.preventDefault(); // Stop Page Reloading
hero && hero.scrollIntoView();
}}
>
Hero
</a>
// Rest of Code
function Hero() {
return (
<section id="hero">
<h1>Hero Section</h1>
</section>
);
}
and to scroll to a section using a url path you would have to get the extract the path from url and scroll to the section that has that specific path as an id
useEffect(() => {
let url = window.location.href.split("/");
let target = url[url.length - 1].toLowerCase();
let element = document.getElementById(target);
element && element.scrollIntoView({ behavior: "smooth", block: "start"});
}, []);
CodeSandbox here
Hope This Helps
To allow the link to update in the address bar, use the answer from #Abdullah Abid but change the <a> tags to <link> and the href to to.
See my ammendment to Abdullah's Sandbox Here

React JSX expressions must have a parent element error when adding a second <div>

When I try to add another react returns the error JSX Expressions must have one parent element. I don't see why this is as it has a parent element.
return (
<div className="loginButton">
<header className="loginButton">
<button className='discordLogin' id='login'
href="link-here"></button>
</header>
</div>
<div className="App">
<header className="App-header">
<img key={speed} src={logo} style={animationStyle} className="App-logo-circle" id='spinnerLogo'
alt="Spinning logo" />
<p>Hello, and welcome to the begining of the Swiss Plus Website. <strong>We hope you enjoy your stay</strong>
</p>
<button className='App-button' id='fastLogoButton' onClick={faster}>Increase Spin Speed!</button>
<button className='App-button' id='slowLogoButton' onClick={slower}>Decrease Spin Speed!</button>
</header>
</div>
);
PS. The error happens at the ) of the return.
You have this error because you are returning two elements simultaneously.
Both your divs need to be wrap in a parent element.
You could use React.Fragment to do this. As mentioned in the docs(https://reactjs.org/docs/react-api.html#reactfragment)
The React.Fragment component lets you return multiple elements in a render()
method without creating an additional DOM element
return(
<React.Fragment>
<div className="loginButton">
<header className="loginButton">
<button className='discordLogin' id='login'
href="link-here"></button>
</header>
</div>
<div className="App">
<header className="App-header">
<img key={speed} src={logo} style={animationStyle} className="App-logo-circle"
id='spinnerLogo'
alt="Spinning logo"
/>
<p>Hello, and welcome to the begining of the Swiss Plus Website. <strong>We hope
you enjoy your stay</strong>
</p>
<button className='App-button' id='fastLogoButton' onClick={faster}>
Increase Spin Speed!
</button>
<button className='App-button' id='slowLogoButton' onClick={slower}>
Decrease SpinSpeed!
</button>
</header>
</div>
</React.Fragment>
);
React components require you to return only one element. A common pattern in React is for a component to return multiple elements. Fragments let you group a list of children without adding extra nodes to the DOM.
return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
);
Usually these elements are wrapped for example inside a div. In most cases the wrapper div is “irrelevant” and is only added because React components require you to return only one element. Read more on fragment and check official documentation.

Categories