Hi all,
I’m trying to do what I feel like should be simple. I’ve looked at a few threads but nothing seems to work nicely. I have a
<DesktopNav/> and a <MobileNav/> component
I want to render when screen size is < 500px and render when screen size is greater than say 768px. The numbers are kind of irrelevant. I was using the useEffect hook and window.matchMedia to do this.
Here is the code for my mobile-nav component:
import React, { useEffect } from "react";
import { css, connect, useConnect, styled } from "frontity";
import { getDisplayType } from "./../../../util/util";
const MobileNav = (props) => {
const { state, actions } = useConnect();
useEffect(() => {
const windowResized = () => {
if(props.type === getDisplayType()) {
actions.theme.setShowMobile(true);
} else {
actions.theme.setShowMobile(false);
}
};
document.defaultView.addEventListener('resize', windowResized);
windowResized();
return () => {
document.removeEventListener('click', windowResized);
};
});
return (
<Header visible={state.theme.showMobile}>
Mobile Nav
</Header>
);
};
export default connect(MobileNav,{ injectProps: false });
const Header = styled.header`
display: ${props => props.visible === true ? 'flex' : 'none'};
align-items: center;
justify-content: space-between;
height: 60px !important;
width: auto;
position: fixed;
top: 0px;
right: 0;
left: 0;
z-index: 99999;
background-color: #FFFFFF;
padding: 0 15px;
`;
I have similar code in my DesktopNav and then in my index.js:
state: {
/**
* State is where the packages store their default settings and other
* relevant state. It is scoped to the `theme` namespace.
*/
theme: {
autoPrefetch: "in-view",
menu: [],
showMobile: false,
showDesktop: false,
isMobileMenuOpen: false,
featured: {
showOnList: false,
showOnPost: false,
},
},
},
/**
* Actions are functions that modify the state or deal with other parts of
* Frontity like libraries.
*/
actions: {
theme: {
// special Frontity action fired to prepare the state for the React render made in the server
beforeSSR: async ({actions}) => {
// All received data are populated in state.source and are accessible using the methods like the handler in libraries.source
// await actions.source.fetch('http://ripple-web.lndo.site/wp-json/menus/v1/menus/footer-about-us') // this invokes our footerMenuHandler
await actions.source.fetch('menus/footer-menu') // /menus/v1/menus/<slug> data for a specific menu location.
await actions.source.fetch('all-categories')
},
setShowMobile: ({ state }) => value => {
state.theme.showMobile = value;
},
setShowDesktop: ({ state }) => value => {
state.theme.showDesktop = value;
},
toggleMobileMenu: ({ state }) => {
state.theme.isMobileMenuOpen = !state.theme.isMobileMenuOpen;
},
closeMobileMenu: ({ state }) => {
state.theme.isMobileMenuOpen = false;
},
},
},
Basically I’m updating some state variables to show either menu, you can see that I’m altering the css display property based on the state value which I’m passing as a prop. This works but each time I load the page / refresh the browser the component flickers from invisible to visible.
I guess this leads to the bigger question of is there a way to do this on the server side? What I’m trying to do with useEffect won’t work on the server because I can’t access the window which is needed by my calls to matchMedia.
I feel like I’m spending lots of time on what should be simple things with Frontity. Anyone else have any thoughts on this?