Gatsby not loading useEffect function in production - javascript

I'm creating a website using Gatsby.js.
In my component, I'd created animation using Gsap, inside useEffect function.
While debugging, all works. In production the useEffect function not running, what follows to not showing animations.
What I should do?
Any ideas?
Thanks for answers!
My component:
import React, { useRef, useEffect } from "react"
import styled from "styled-components"
import gsap from "gsap"
import WhatEver from "../../../static/whatever.svg"
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faArrowDown } from '#fortawesome/free-solid-svg-icons'
import scrollTo from 'gatsby-plugin-smoothscroll';
const HeaderWrapper = styled.header`
width: 100%;
height: 100vh;
min-height: 150px;
padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: rgb(255, 216, 41);
`
const HeaderButton = styled.button`
display: block;
margin: 40px auto;
border: 2px solid #000000;
`
const HeaderComponent = () => {
const animWrapper = useRef(null)
useEffect(() => {
const [elements] = animWrapper.current.children
const what = elements.getElementById('What')
const ever = elements.getElementById('Ever')
const button = document.getElementById('header-button')
const icon = document.getElementById('header-icon')
const whatChildrens = what.children
const everChildrens = ever.children
const allChildrens = [...whatChildrens, ...everChildrens]
gsap.set([...allChildrens, button], { autoAlpha: 0 })
const timeLine = gsap.timeline({ defaults: { ease: 'power3.inOut' } })
timeLine
.to(whatChildrens, { autoAlpha: 1, duration: 0.75 })
.to(everChildrens, { autoAlpha: 1, stagger: 0.025 })
.to(button, { autoAlpha: 1 })
}, [])
return (
<HeaderWrapper className="header" id="main-header">
<div ref={animWrapper} id="header-logo-wrapper">
<WhatEver style={{width: '100%'}}/>
<HeaderButton id="header-button" onClick={() => scrollTo('#poznaj-nas')}>
<FontAwesomeIcon icon={faArrowDown} id="header-icon"/>
</HeaderButton>
</div>
</HeaderWrapper>
)
}
export default HeaderComponent

I think what is happening is that the gsap library is getting tree shaken out of the production build. I would either try adjusting your webpack settings to make sure that it is not removed, or include it like this instead:
const gsap = require("gsap")
Which in my experience has prevented libraries from being tree shaken out.

I was facing this issue and it got resolved just by following the steps:
If you are trying to open the html directly without any web server then useEffect won't be called.
Only way to solve this issue is by running a webserver and serve the html from the server.
I am using a mac system so run the python server using the command inside the public folder:
python -m SimpleHTTPServer 8000
then open it using localhost:8000

Related

onClick event not firing in my styled component in my react app

I'am trying to trigger an onCick event that i passed to my style component icon tag but for some reason the event does not get triggered when the icon is clicked. I've tried raping it in a div and passing the onClick event to the div instead but still get the same result.
here is the code:
import React from "react";
import { useState } from "react";
import StyledNav, {NavbarhamButton} from "./style/Navbar.styled";
const Navbar = () => {
const [NavOpen, setNavOpen] = useState(false);
return (
<StyledNav>
<NavbarhamButton
className="fas fa-bars"
onclick={() => setNavOpen(!NavOpen)}
/>
</StyledNav>
);
};
export default Navbar;
Here is the styled components:
import { Link } from "react-router-dom";
import styled from "styled-components";
import { theme } from "../../theme";
const StyledNav = styled.div``;
export const NavbarhamButton = styled.i`
position: absolute;
top: 0;
left: 0;
margin: 1rem;
font-size: 2rem;
color: white;
#media screen and (min-width: 600px) {
display: none;
}
z-index: 2;
`;
I just started to use style components of recent so am still trying to wrap my head around it please correct me if am doing something wrong thanks.
Try changing the prop to onClick for <NavbarhamButton />. You may also need to use a base component other than i. So you might want to try styled.button instead of styled.i.

How can I make this scroll To Top upon re-rendering while keeping the headers reactive functionality?

This is alot of code but it is the minimal way that I could think of reproducing my problem.
view in sandbox: https://codesandbox.io/s/silly-kare-j0kmz
I would like the header bar to hide upon scrolling. The problem is everytime I click on a box to go to another route, or click header to come back to the home route, the scroll bar stays where it was before. That is everytime I move from route to route, the scrollbar does not move to the top.
I was able to fix this problem with the scrollToTop code, But in order to make it scroll to the top, I need to remove "overflow-y" from App.css, which stops my header from reacting onScroll.
I came to realize this is because window is perhaps a BOM object and only targets the browser window itself, not div class which I have assigned onScroll to.
So it seems I can do either OR, but not both functions together. I would like both to happen, The scrolToTop on location change AND to keeep the Header Reacting to the onScroll method. How can I do that?
App.js ---------------------------------------------------
Provides routing to First.js and Second.js. Also has the onScroll method. That is when you scroll up, the header appears, and when you scroll up the header disapears. Along with some routing to 2 simple components.
import './App.css';
import {useState, useEffect, useRef} from 'react';
import { Route, Routes} from 'react-router-dom';
import Second from "./Second/Second";
import First from "./First/First";
import Header from './Header/Header';
import ScrollToTop from './ScrollToTop/ScrollToTop'
function App() {
const prevScrollY = useRef(0);
const [goingUp, setGoingUp] = useState(true);
const [HeaderisVisible, setHeaderIsVisible] = useState(0);
const onScroll = (e) => {
const currentScrollY = e.target.scrollTop;
if (prevScrollY.current < currentScrollY && goingUp) {
setGoingUp(false);
}
if (prevScrollY.current > currentScrollY && !goingUp) {
setGoingUp(true);
}
prevScrollY.current = currentScrollY;
console.log(goingUp, currentScrollY);
};
return (
<div className="App" onScroll = {onScroll}>
<ScrollToTop/>
<Routes>
<Route path = '/' exact element = {<First GoingUp = {goingUp}/>}/>
<Route path = '/second' element = {<Second GoingUp = {goingUp}/>} />
<Route path = '*'>
NOT FOUND
</Route>
</Routes>
</div>
);
}
export default App;
Header.js -------------------------------------------------
Header takes props from the state initialized in App.js containing a true or flase variable. and uses that in a conditional to either show or hide the header. Also on clicking the header you go back to the home page.
import './Header.css';
import {useState, useEffect} from 'react';
import {Link} from 'react-router-dom';
function Header(props) {
const [HeaderisVisible, setHeaderIsVisible] = useState(0);
useEffect(() => {
if(props.GoingUp == true){
setHeaderIsVisible(0);
}else{
setHeaderIsVisible(-199);
}
}, [props.GoingUp]);
return (
<Link to = '/'><div className = "Header"
style = {{
top: `${HeaderisVisible}px`
}}>
</div> </Link>
);
}
export default Header;
First.js --------------------------------------------------
First is a simple component that just displays some divs. Each black div will route the the second page.
import './First.css';
import {Link} from 'react-router-dom';
import Header from '../Header/Header';
function First(props) {
return (
<div className="First">
<Header GoingUp = {props.GoingUp}/>
<Link to = '/second'><div className = "entity"></div></Link>
<Link to = '/second'><div className = "entity"></div></Link>
<Link to = '/second'><div className = "entity"></div></Link>
<Link to = '/second'><div className = "entity"></div></Link>
<Link to = '/second'><div className = "entity"></div></Link>
</div>
);
}
export default First;
Second.js -------------------------------------------------
Second is a simple component that just displays some red divs.
import './Second.css';
import { Route, Routes, Link} from 'react-router-dom';
import Header from '../Header/Header';
function Second(props) {
return (
<div className="Second">
<Header GoingUp = {props.GoingUp}/>
<div className = "entity2"></div>
<div className = "entity2"></div>
<div className = "entity2"></div>
<div className = "entity2"></div>
<div className = "entity2"></div>
</div>
);
}
export default Second;
ScrollToTop.js --------------------------------------------
Gets the location via the url search path, and scrolls to the top of the page on every search.
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default function ScrollToTop(props) {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
First.css
-----------------------------------
.entity{
height: 200px;
margin: auto;
width: 200px;
border: 2px solid black;
background-color: black;
margin-top: 200px;
}
Second.css
-------------------------------------
.Second{
background-color: lightgreen;
}
.entity2{
height: 200px;
margin: auto;
width: 200px;
border: 2px solid black;
background-color: red;
margin-top: 200px;
}
Header.css
------------------------------------
.Header{
background-color: brown;
height: 200px;
position: fixed;
width: calc(100% - 17px);
}
App.css
-------------------------------------
html{
margin: 0;
}
body{
margin: 0;
}
.App{
overflow-y: auto;
background-color: lightblue;
height: 100vh;
}
I was able to solve my problem by replacing window.scrollTo(...) with the following: props.refProp.current.scrollTop = 0; inside of scrollToTop function.
export default function ScrollToTop(props) {
const { pathname } = useLocation();
useEffect(() => {
props.refProp.current.scrollTop = 0;
}, [pathname]);
return null;
}

Styled Components Nested components erroring

I am trying to workout why this is erroring.
Although If I do not have CardWrapper wrapping around CardImage the image is displaying.
import React from 'react'
import styled, { css } from 'styled-components'
const CardWrapper = styled.div`
background-color: yellow;
border-color: 1px solid red;
position: relative;
`
const CardImage = styled.img`
height: auto;
width: 100%;
`
const Card = props => {
return (
<CardWrapper>
<CardImage src={props.data.imageUrl}/>
</CardWrapper>
)
}
export default Card;
App.js
<Card data={{imageUrl: 'https://via.placeholder.com/630x354', logoUrl: "https://via.placeholder.com/100x100", text: "test"}}/>
Error
./src/Components/Card/Card.js
Error: Cannot find module '/Users/max/test/test/test/node_modules/babel-preset-react-app/node_modules/#babel/core/lib/index.js'. Please verify that the package.json has a valid "main" entry
Looks like you need to install a Node.js package. In your terminal, navigate to the project's root directory and run:
npm install babel-preset-react-app

Same code generating different snapshots on different machines

We're using git for version control, so the code is the same. But if I generate snapshots, and my coworkers run the tests, they all fail on the snapshot part. Why can this happen?
Example component
import React from 'react';
import styled from 'styled-components';
import classnames from 'classnames';
import { colors } from '../../utils/css';
const ProgressIcon = ({ className, progress, color }) => (
<div className={className}>
<div className={classnames('background', color)}>
<div className={classnames('icon', progress, color)}/>
</div>
</div>
);
export const StyledProgressIcon = styled(ProgressIcon)`
width: 12.8px;
height: 12.8px;
margin: 0;
div {
margin: 0;
}
.background.white {
border: 2px solid ${colors.LG_WHITE};
}
.background.gray {
border: 2px solid ${colors.LG_GRAY_2};
}
.background {
height: 100%;
width: 100%;
border-radius: 50%;
box-sizing: border-box;
.icon {
height: 100%;
}
.icon.white {
background: ${colors.LG_WHITE};
}
.icon.gray {
background: ${colors.LG_GRAY_2};
}
.icon.full {
width: 100%;
}
.icon.half {
width: 50%;
}
.icon.empty {
width: 0;
}
}
`;
Test
import React from 'react';
import { shallow } from 'enzyme';
import { StyledProgressIcon as ProgressIcon } from '../ProgressIcon';
describe('<ProgressIcon/>',
() => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<ProgressIcon progress={'full'} color={'gray'}/>);
});
it('should match the snapshot', () => {
expect(wrapper).toMatchSnapshot();
});
});
I'm comparing the snapshots created by my coworkers (Everybody else's tests are passing with the exact same snapshots, and code. It only fails on my machine)
Here is the log
FAIL src/components/ProgressIcon/test/ProgressIcon.test.js
● <ProgressIcon/> › should match the snapshot
expect(received).toMatchSnapshot()
Snapshot name: `<ProgressIcon/> should match the snapshot 1`
- Snapshot
+ Received
## -4,11 +4,11 ##
Object {
"$$typeof": Symbol(react.forward_ref),
"attrs": Array [],
"componentStyle": ComponentStyle {
"componentId": "sc-bdVaJa",
- "isStatic": false,
+ "isStatic": true,
"rules": Array [
"
width: 12.8px;
height: 12.8px;
margin: 0;
## -69,11 +69,10 ##
"foldedComponentIds": Array [],
"render": [Function],
"styledComponentId": "sc-bdVaJa",
"target": [Function],
"toString": [Function],
- "usesTheme": false,
"warnTooManyClasses": [Function],
"withComponent": [Function],
}
}
forwardedRef={null}
10 | });
11 | it('should match the snapshot', () => {
> 12 | expect(wrapper).toMatchSnapshot();
| ^
13 | });
14 | });
15 |
at Object.toMatchSnapshot (src/components/ProgressIcon/test/ProgressIcon.test.js:12:23)
And the reverse is if I generate snapshots, and my coworkers test. Why is this happening and how can I fix this?
There is a version mismatch in your styled-components lib dependency. As explained
here
It is the styled component's shallow render that shows you that "isStatic": false value
Both of you need to sync up your dependencies. First
make sure that both have the same package.json.
Then the surefire way to do this is. In one of your computers
Remove node_modules
delete package-lock.json
Run npm install
Commit your package-lock.json! (ignore if no changes)
Go to all other PCs.
Pull in the changes to package lock json (reject all local and accept all remote changes).
Remove node_modules.
Run npm install.
Now run your tests and check, the snapshots should be equal.
I fixed it by installing https://github.com/styled-components/jest-styled-components
Although I've followed the above mentioned points as well but I think this one should also fix the issue.
yarn add --dev jest-styled-components
Usage
import React from 'react'
import styled from 'styled-components'
import renderer from 'react-test-renderer'
import 'jest-styled-components'
const Button = styled.button`
color: red;
`
test('it works', () => {
const tree = renderer.create(<Button />).toJSON()
expect(tree).toMatchSnapshot()
expect(tree).toHaveStyleRule('color', 'red')
})

Testing DOM in Enzyme

Let's say I have a tiny component like this:
Button.js
import React from 'react';
import './Button.css';
export default class Button extends React.Component {
render() {
return (
<a href={ this.props.url } className={`button button-${ this.props.type }`}>
{ this.props.content }
</a>
);
}
}
And there's some super basic styling like this:
Button.css
.button {
color: white;
padding: 1em;
border-radius: 5px;
text-decoration: none;
}
.button-primary {
background-color: red;
}
.button-primary:hover {
background-color: darkred
}
.button-secondary {
background-color: aqua;
color: black;
}
.button-secondary:hover {
background-color: darkcyan;
color: white;
}
And let's say I want to write some tests for this:
Button.test.js
import React from 'react';
import Enzyme, {shallow, mount} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter: new Adapter()});
import Button from './Button';
import './Button.css';
// Render buttons
const primaryButton = mount(
<Button
content="Primary button"
url="http://www.amazon.co.uk"
type="primary"
/>
);
const secondaryButton = mount(
<Button
content="Secondary button"
url="http://www.ebay.co.uk"
type="secondary"
/>
);
it('should exist', () => {
expect(primaryButton).toBeDefined();
expect(secondaryButton).toBeDefined();
});
it('should display text in the button', () => {
expect(primaryButton.text()).toEqual('Primary button');
});
it('should have the correct CSS classes', () => {
expect(primaryButton.find('.button').hasClass('button-primary')).toEqual(true);
expect(secondaryButton.find('.button').hasClass('button-secondary')).toEqual(true);
});
I've set this up using react-create-app and all the above works perfectly.
My question is: how do I test that what is getting rendered looks correct? For example, in this case I would want to make sure that the buttons have the correct background colours defined in the CSS file and that they have the correct border radius. This will prevent other developers accidentally overriding critical styling for example.
I was under the impression that Enzyme did this out of the box, but I cannot understand how to interrogate the virtual DOM which I assume is happening in the background? I thought that JSDOM was automatically running and I'm executing this from the CLI which is a Node environment.
I've tried this so far:
it('should have the correct background colours', () => {
const domNode = primaryButton.find('.button').at(0).getDOMNode();
const background = getComputedStyle(domNode).getPropertyValue('background');
expect(background).toBe('red');
});
But background is returned blank, in fact if I do console.log(getComputedStyle(domNode)) I get this returned which seems to be missing the styles:
console.log src/modules/Button/Button.test.js:42
CSSStyleDeclaration {
_values: {},
_importants: {},
_length: 0,
_onChange: [Function] }
The getDOMNode of an enzyme wrapper gets you the corresponding DOM node.
You can then use getComputedStyle to get the style of that DOM:
const renderedComponent = mount(<MyComponent /);
const domNode = renderedComponent.find('div').at(0).getDOMNode();
const background = getComputedStyle(domNode).getPropertyValue('background');
expect(background).toBe('red');

Categories

Resources