import React, { Component } from 'react';
import './App.css';
import Home from './Components/Home/Home';
import Explainers from './Components/Explainers/Explainers';
import VideoCreation from './Components/VideoCreation/VideoCreation';
import Video from './Components/Video/Video';
import Footer from './Components/Footer/Footer';
class App extends Component {
constructor(props){
super(props);
this.state = {isExplainers:false, isVideoExp:false }
this.handleScroll = this.handleScroll.bind(this);
}
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnMount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll=()=>{
console.log("scroll handle")
this.setState({isExplainers:true});
window.addEventListener('scroll', this.videoScroll);
}
videoScroll = () =>{
console.log("scroll of Video");
this.setState({isVideoExp:true});
window.addEventListener('scroll', this.ourVideoScroll);
}
ourVideoScroll=()=>{
console.log("our Video Scroll");
}
render() {
const explainersClass = this.state.isExplainers ? "explainerAfter" : "explainer";
const creationClass = this.state.isVideoExp ? "videoCreationAfter" : "videoCreation";
const ourVideoClass = this.state.isExplainers ? "videoCreationAfter" : "videoCreation";
return (
<div className="App">
<Home onScroll = {this.handleScroll}/>
<div className={explainersClass} onScroll={this.videoScroll}><Explainers /></div>
<div className={creationClass} onScroll={this.ourVideoScroll}><VideoCreation /></div>
<div className={ ourVideoClass } > <Video /></div>
<Footer />
</div>
);
}
}
export default App;
In this i have three onScroll functions where i need a functionality of working one after the other should update once it reaches the end of the component all are getting updated at once any wrong in my code ? or any other forms or methods for doing this using other frameworks or else ?
You need not add scroll event for each function, rather you can just call it from the previous function. Also since setState is async, you would call these function from the setState callback which is executed after setState is completed
class App extends Component {
constructor(props){
super(props);
this.state = {isExplainers:false, isVideoExp:false }
this.handleScroll = this.handleScroll.bind(this);
}
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnMount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll=(e)=>{
console.log("scroll handle");
const explainer = React.findDOMNode(this.explainer);
const home = React.findDOMNode(this.home);
if(home.scrollTop === explainer.offsetTop) {
this.setState({ isExplainers : true });
}
}
videoScroll = () => {
const explainer = React.findDOMNode(this.explainer);
const video = React.findDOMNode(this.video);
if(explainer.scrollTop === video.offsetTop) {
this.setState({ isVideoExp : true });
}
}
ourVideoScroll=()=>{
console.log("our Video Scroll");
const ourVideo = React.findDOMNode(this.ourVideo);
const video = React.findDOMNode(this.video);
if(video.scrollTop === ourVideo.offsetTop) {
// take action here
}
}
render() {
const explainersClass = this.state.isExplainers ? "explainerAfter" : "explainer";
const creationClass = this.state.isVideoExp ? "videoCreationAfter" : "videoCreation";
const ourVideoClass = this.state.isExplainers ? "videoCreationAfter" : "videoCreation";
return (
<div className="App">
<Home ref={ref => this.home = ref} onScroll = {this.handleScroll}/>
<div className={explainersClass} ref={ref => this.explainer = ref} onScroll={this.videoScroll}><Explainers /></div>
<div className={creationClass} ref={ref => this.video = ref} onScroll={this.ourVideoScroll}><VideoCreation /></div>
<div className={ ourVideoClass } ref={ref => this.ourVideo = ref}> <Video /></div>
<Footer />
</div>
);
}
}
export default App;
Related
I have a question regarding how I can fix 'Can't perform a React state update' error message. I did read a little further into the issue and states it is only a warning. Please note, I'm a beginner at React. Here is the problem as follows.
I have a header component that is comprised of a navbar that has two states for toggling the mobile navigation menu button and another for changing background-color on scroll. I implemented navbar toggle functionality and I started receiving the so-called error in JS console. Upon further inspection, I have determined that it is something to do with my toggle state. Any help will be appreciated. Thanks in advance!
import React, { useState } from 'react';
import { Icon } from 'react-icons-kit';
import {bars} from 'react-icons-kit/fa/bars';
import {times} from 'react-icons-kit/fa/times';
import {chevronCircleDown} from 'react-icons-kit/fa/chevronCircleDown';
const Header = (props) => {
const [toggle, setToggle] = useState(false);
const [navbar, setNavbar] = useState(false);
const handleToggle = () => {
setToggle(!toggle);
}
const changeBackground = () => {
if(window.scrollY >= 60) {
setNavbar(true);
}
else {
setNavbar(false);
}
}
window.addEventListener('scroll', changeBackground);
if(props.data){
var description = props.data.description;
var navigation = props.data.navigation.map(item => {
return <li key={item.linkname} className="nav-item"><a href={item.href} className={item.className}>{item.linkname}</a></li>
});
}
return (
<header id="home" className="main-header">
<div className="container">
<nav className={navbar ? 'navbar nav-bg' : 'navbar'} aria-label="Main Navigation" id="navbar">
<ul className={toggle ? 'navbar-nav active' : 'navbar-nav'} id="nav">
{navigation}
</ul>
<button className="btn-mobile-nav" type="button" aria-controls="nav" aria-expanded={toggle ? 'true' : 'false'} aria-label="Mobile Navigation button" title="Mobile menu button" onClick={handleToggle}>{toggle ? <Icon icon={times} size={24} title="Close Menu"/> : <Icon icon={bars} size={24} title="Open Menu"/> }</button>
</nav>
</div>
<div className="header-content d-flex flex-column">
<div>
<h1 className="header-title"><span className="typed"></span></h1>
<p className="header-summary">{description}</p>
</div>
</div>
<Icon icon={chevronCircleDown} size={54}/>
</header>
);
}
export default Header;
import React from 'react';
import SkipNav from './Components/SkipNav';
import Header from './Components/Header';
import Footer from './Components/Footer';
import About from './Components/About';
import Resume from './Components/Resume';
import Portfolio from './Components/Portfolio';
import Contact from './Components/Contact';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
resumeData: [],
recipName: '',
recipEmail: '',
recipSubject: '',
recipMessage: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleCaptchaChange = this.handleCaptchaChange.bind(this);
this.handleEmailSent = this.handleEmailSent.bind(this);
}
getResumeData = () => {
fetch('/data.json')
.then(response => {
return response.json()
})
.then(data => {
this.setState({
resumeData: data
});
})
.catch(error => {
console.log(error)
alert(`Unable to retrieve data! See JS console for details. Error:${error}`)
})
}
handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value });
}
handleCaptchaChange = (value) => {
console.log("Captcha value:", value);
}
handleEmailSent = (event) => {
event.preventDefault();
if (this.state.recipName === '' || this.state.recipEmail === '' || this.state.recipSubject === '' || this.state.recipMessage === '') {
console.log('All fields required!')
alert('All fields are required!');
return;
}
let data = {
recipName: this.state.recipName,
recipEmail: this.state.recipEmail,
recipSubject: this.state.recipSubject,
recipMessage: this.state.recipMessage
};
console.log(data);
fetch (`https://api.eahassan.me/sendEmail`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then((response) => {
console.log(response.data);
alert("E-Mail sent successfully!");
window.location.reload();
})
.catch((error) => console.log("E-Mail Failure - Error:", error));
}
componentDidMount = () => {
this.getResumeData();
}
render() {
return (
<div className="App">
<SkipNav title="Skip to main content"/>
<Header data={this.state.resumeData.main}/>
<main id="mainContent">
<About data={this.state.resumeData.main} title="About Me"/>
<Resume data={this.state.resumeData.resume} eduTitle="Education" workTitle="Work" skillTitle="Skills"/>
<Portfolio data={this.state.resumeData.portfolio}/>
<Contact data={this.state.resumeData.main} recommendData={this.state.resumeData.recommendations} captchaChange={this.handleCaptchaChange} recipName={this.state.recipName} recipEmail={this.state.recipEmail} recipSubject={this.state.recipSubject} recipMessage={this.state.recipMessage} EmailSend={this.handleEmailSent} change={this.handleChange}/>
</main>
<Footer data={this.state.resumeData.main}/>
</div>
);
}
}
export default 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>
You are unconditionally adding a scroll event listener in the body of the component. This should be added in an useEffect hook and cleaned up when the component unmounts. For scroll events that are generally very noisy, you'll want to make these passive listeners.
useEffect(() => {
const changeBackground = () => {
setNavbar(window.scrollY >= 60);
}
window.addEventListener('scroll', changeBackground, { passive: true });
return () => window.removeEventListener('scroll', changeBackground, { passive: true });
}, []);
The App component's constructor function was being rendered twice.
I removed <React.StrictMode> from index.js and the error went away.
Problem solved!
https://arange.github.io/2020-06-15-react-component-s-constructor-rendered-twice-leading-to-bugs-using-axios-interceptor/
How we can change the handlerOnMouseMove inside other handler (in my example OnClick).
I show an example below;
normally when I do this this.handleMouseMove = undefined; it should disable my event onMouseMove but unfortunately it is not working.
import React from 'react'
import {render} from 'react-dom'
import './BasicComponent.css'
class BasicComponent extends React.Component {
constructor (props){
super(props)
this.state = {
id: "id",
title: "component",
inputs: [],
outputs: [],
}
this.handleClick = this.handleClick.bind(this)
this.handleMouseDown = this.handleMouseDown.bind(this)
this.handleMouseUp = this.handleMouseUp.bind(this)
this.handleMouseMove = this.handleMouseMove.bind(this)
}
render() {
console.log("render");
return(
<div className="component"
onMouseDown={ this.handleMouseDown }
onMouseUp={ this.handleMouseUp }
onMouseMove={ this.handleMouseMove }>
<div className="title">Title</div>
<div className="id">ID: c_356545454</div>
<div className="inputs">inputs</div>
<div className="core">core</div>
<div className="outputs">outputs</div>
<button onClick={ this.handleClick } >Disable handler onMouseMove</button>
</div>
);
}
handleClick() {
this.handleMouseMove = undefined; // <===== this not disable the call on handleMouseMove ???
console.log("handleClick : handleMouseMove is disabled");
}
handleMouseDown() {
console.log("handleMouseDown");
}
handleMouseUp() {
console.log("handleMouseUp");
}
handleMouseMove() {
console.log("handleMouseMove");
}
}
export default BasicComponent
Try this:
class BasicComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
id: "id",
title: "component",
inputs: [],
outputs: [],
disableMouseMove: false,
};
this.handleClick = this.handleClick.bind(this);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.handleMouseMove = this.handleMouseMove.bind(this);
}
render() {
const { disableMouseMove } = this.state;
return (
<div
className="component"
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
onMouseMove={disableMouseMove ? () => {} : this.handleMouseMove}
>
<div className="title">Title</div>
<div className="id">ID: c_356545454</div>
<div className="inputs">inputs</div>
<div className="core">core</div>
<div className="outputs">outputs</div>
<button onClick={this.handleClick}>Disable handler onMouseMove</button>
</div>
);
}
handleClick() {
this.setState({ disableMouseMove: true }); // <===== this not disable the call on handleMouseMove ???
console.log("handleClick : handleMouseMove is disabled");
}
}
You can createRef for the wrapper div you are tracking the "mousemove", add the "mousemove" event listener for that ref once component mounts and remove it once the button is clicked. Hint, there is no more "onMouseMove" for the wrapping div. Below I also replaced your class methods with arrow functions in order to avoid binding them.
export default class BasicComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
id: "id",
title: "component",
inputs: [],
outputs: [],
}
this.myRef = React.createRef()
}
componentDidMount(){
this.myRef.current.addEventListener('mousemove', this.handleMouseMove)
}
handleClick = () => {
this.myRef.current.removeEventListener('mousemove', this.handleMouseMove)
console.log("handleClick : handleMouseMove is disabled");
}
handleMouseDown = () => {
console.log("handleMouseDown");
}
handleMouseUp = () => {
console.log("handleMouseUp");
}
handleMouseMove = () => {
console.log("handleMouseMove");
}
render() {
console.log("render");
return (
<div ref={this.myRef} className="component"
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
>
<div className="title">Title</div>
<div className="id">ID: c_356545454</div>
<div className="inputs">inputs</div>
<div className="core">core</div>
<div className="outputs">outputs</div>
<button onClick={this.handleClick} >Disable handler
onMouseMove
</button>
</div>
);
}
}
I cant figure out why my Login component is not re-rendering what is on the page. The state is changed to loginShow after I click on a "Log In" button on top of my form.
import React from 'react';
import SignUp from '../SignUp';
import Cards from '../Articles/Cards';
import Login from '../LogIn';
export default class Gecko extends React.Component {
constructor(props) {
super(props);
this.state = { requestedPostsThatWeGotFromGecko: null, }
this.clickMe = this.clickMe.bind(this)
this.state = {
loginStatus: "loginHide",
authType: "signup"
};
this.loginClose = this.loginClose.bind(this);
this.loginOpen = this.loginOpen.bind(this);
}
loginClose(e) {
e.stopPropagation();
this.setState({
loginStatus: "loginHide"
});
}
loginOpen() {
this.setState({
loginStatus: "loginShow"
});
}
clickMe = () => {
const {requestedPostsThatWeGotFromGecko} = this.state;
this.setState({ requestedPostsThatWeGotFromGecko: !requestedPostsThatWeGotFromGecko })
}
/* mainLogIn = () => {
const {loginStatus} = this.state;
this.setState({ loginStatus: 'loginHide' })
} */
render() {
const { requestedPostsThatWeGotFromGecko } = this.state;
const { loginStatus } = this.state;
console.log(loginStatus);
// const { authType } = this.state;
// if (loginStatus === "loginHide") return <SignUp login={() => this.clickMe()} />
// if (requestedPostsThatWeGotFromGecko.props === true) return <Cards />
if (loginStatus !== "loginShow") return (
<div className="gecko">
{requestedPostsThatWeGotFromGecko ? (
<Cards />
): (
<SignUp login={() => this.clickMe()} />
)
}
</div>
);
if (loginStatus === "loginShow") return <Login />
}
}
I believe the issue lies where I am trying to set what is being displayed using the conditional operator at the end of the code above. I have included where I am setting the state and props from my other components in the code below.
const onClick = () => {
this.props.login();
console.log('rich');
}
const mainLogIn = () => {
this.setState({
loginStatus: "loginShow"
});
console.log('rich1');
console.log(this.state);
}
const onClick = () => {
this.props.login();
console.log('rich');
}
const mainSignUp = () => {
this.props.signup();
this.setState({
loginStatus: "loginHide"
});
console.log('rich2');
}
Why is onClick={this.onToggleMenuModal} not triggering on div id="freezer", whilst it is in my components by passing onToggleMenuModal={this.handleToggleMenuModal}?
Adding onToggleMenuModal={this.handleToggleMenuModal} to returned an error of Unknown Prop Warning
Here is the code...
import React from 'react';
import PropTypes from 'prop-types';
...
class Template extends React.Component {
constructor(props) {
super(props)
this.state = {
menuModal: false,
loading: 'is-loading'
}
this.handleToggleMenuModal = this.handleToggleMenuModal.bind(this)
}
componentDidMount () {
this.timeoutId = setTimeout(() => {
this.setState({loading: ''});
}, 100);
}
componentWillUnmount () {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
}
handleToggleMenuModal() {
this.setState({
menuModal: !this.state.menuModal
})
}
render() {
const { children } = this.props
return (
<div id="perspective" className={`showMenu ${this.state.loading} ${this.state.menuModal ? 'animate modalview' : ''}`}>
<Helmet>
...
</Helmet>
<div id="container">
<Header onToggleMenuModal={this.handleToggleMenuModal} />
<div id="wrapper">
{children()}
<Footer />
</div>
<div id="freezer" onClick={this.onToggleMenuModal}></div>
</div>
</div>
)
}
}
Template.propTypes = {
children: PropTypes.func,
}
export default Template
You must put onClick inside arrow fuction like :
onClick={() => {this.onToggleMenuModal}}
Check this solution and let me know if it work for you or not.
import React from 'react';
import PropTypes from 'prop-types';
...
class Template extends React.Component {
constructor(props) {
super(props)
this.state = {
menuModal: false,
loading: 'is-loading'
}
this.handleToggleMenuModal = this.handleToggleMenuModal.bind(this)
}
componentDidMount () {
this.timeoutId = setTimeout(() => {
this.setState({loading: ''});
}, 100);
}
componentWillUnmount () {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
}
handleToggleMenuModal() {
this.setState({
menuModal: !this.state.menuModal
})
}
render() {
const { children } = this.props
return (
<div id="perspective" className={`showMenu ${this.state.loading} ${this.state.menuModal ? 'animate modalview' : ''}`}>
<Helmet>
...
</Helmet>
<div id="container">
<Header onToggleMenuModal={this.handleToggleMenuModal} />
<div id="wrapper">
{children()}
<Footer />
</div>
<div id="freezer" onClick={this.onToggleMenuModal}></div>
</div>
</div>
)
}
}
Template.propTypes = {
children: PropTypes.func,
}
export default Template
class App extends Component {
constructor(props){
super(props);
this.state = {isExplainers:false, isVideoExp:false, isOurVideo:false }
this.handleScroll = this.handleScroll.bind(this);
}
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnMount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll=()=>{
const height = document.getElementById('explainers').clientHeight;
const height1 = document.getElementById('video').clientHeight;
console.log("explainers"+height);
console.log("home"+height1)
const explainer = ReactDOM.findDOMNode(this.explainer);
const home = ReactDOM.findDOMNode(this.home);
if(home.scrollTop === explainer.offsetTop) {
this.setState({ isExplainers : true });
}
}
ourVideoScroll=()=>{
const ourVideo = ReactDOM.findDOMNode(this.ourVideo);
const explainer = ReactDOM.findDOMNode(this.explainer);
if(explainer.scrollTop === ourVideo.offsetTop) {
this.setState({isOurVideo:true});
}
}
render() {
const explainersClass = this.state.isExplainers ? "explainerAfter" : "explainer";
// const creationClass = this.state.isVideoExp ? "videoCreationAfter" : "videoCreation";
const ourVideoClass = this.state.isOurVideo ? "videoContainerAfter" : "videoContainer";
return (
<div className="App">
<Home id="home" ref={ref => this.home = ref} onScroll = {this.handleScroll}/>
<div id="explainers" className={explainersClass} ref={ref => this.explainer = ref} onScroll={this.ourVideoScroll}><Explainers /></div>
<div id="video" className={ ourVideoClass } ref={ref => this.ourVideo = ref}> <Video /></div>
<CreateMore />
<Services/>
<Animated />
<Clients/>
<Footer />
</div>
);
}
}
export default App;
There are 7-8 components which should load only when the user reaches the end point of the current div or component how can I achieve this?
This can be done with the help of jQuery but I'm not interested in using that?