Gatsby changes/removes components className after build - reactjs

I tried to add floating bar to the website. And i have a Layout component that used on every page. The Layout component has some navigation logic, graphQL query and the next jsx:
<>
<FloatingBar data={floatingBarData} className="floating-bar" />
<div className="main-container">
<Container>
<Header/>
<Main/>
<Footer>
</Container>
</div>
<div>
<Cookies/>
</div>
<>
So basically, the Floating bar goes first, then all page elements, and cookies.
When i am at the development mode everything seems to be fine and i have the next markup:
But when i run gatsby build, i have the next markup:
So the order of the elements is not changed. But the first div that should have the class="floating-bar" has the class="main-container" and the second div that should have the class="main-container" does not have the class at all. But all inner elements are according to the layout.
I tried to replace Fragments with div, move <FloatingBar/> after main container and it did not help. Also i tried to put this bar inside <div className="main-container"/> and got the following markup:
Seems like it gives to the root div of Floating Bar the className of its sibling.
Only when i put the bar before the inner elements of the main container, so that the markup is next:
<>
<div className="main-container">
<Container>
<FloatingBar data={floatingBarData} className="floating-bar" />
<Header/>
<Main/>
<Footer>
</Container>
</div>
<div>
<Cookies/>
</div>
<>
Now, it works.
The Floating bar component has a state inside to show and hide the bar, and the information about its visibility goes to Session Storoage.
Does anyone knows what exactly is happening?

Related

how to resolve "Prop `id` did not match. Server: "react-tabs-30" Client: "react-tabs-0" console issue?

i am trying tab in next in next.js, but every time i use it it show a console warning link this Prop `id` did not match. Server: "react-tabs-30" Client: "react-tabs-0", i know it isn't effect my app but it is so annoying. how to solve this waring
<Tabs>
<div className="tab-controler ml-sm-auto">
<TabList className="tab-lists list-inline d-flex flex-wrap nav mb-3" style={{ background: '#F8F8F8' }}>
<Tab className={`${CostCalculatorStyle.PEItem} tab-lists__item`}>Buy & Ship for me</Tab>
<Tab className={`${CostCalculatorStyle.PEItem} tab-lists__item`}>Ship for me</Tab>
</TabList>
</div>
<TabPanel key={"tabpanel_ship"}>
<div className="row">
<div className="col-lg-6">
<ShipForMeForm handleFormValue={handleFormValue} handleProductValue={handleProducts} handleRef={handleRef} />
</div>
<div className="col-lg-6 align-self-center">
<div className="costcalc-empty-thumb text-center">
<Image
src="/assets/topNavbarPages/costCalculator.svg"
alt="Cost Calculator"
width="469"
height="288"
/>
</div>
</div>
</div>
</TabPanel>
<TabPanel key={"tabpanel_buy_ship"}>
<div className="row">
<div className="col-lg-6">
<ShipForMeForm handleFormValue={handleFormValue} handleProductValue={handleProducts} handleRef={handleRef} />
</div>
<div className="col-lg-6 align-self-center">
<div className="costcalc-empty-thumb text-center">
<Image
src="/assets/topNavbarPages/costCalculator.svg"
alt="Cost Calculator"
width="469"
height="288"
/>
</div>
</div>
</div>
</TabPanel>
</Tabs>
as you can see i use react-tabs for tab but i also work on react js where i use the same code but it didn't show this console warning. so my question is why it is happing? and how i can solve it ?
In next js i fixed it like that
import dynamic from 'next/dynamic'
const Tabs = dynamic(import('react-tabs').then(mod => mod.Tabs), { ssr: false }) // disable ssr
import { Tab, TabList, TabPanel } from 'react-tabs'
it work for me
The best solution I know of is just to set the id yourself in the <Tabs> component. Ex: <Tabs id={1}>
See https://github.com/chakra-ui/chakra-ui/issues/4328#issuecomment-890525420 for more details and examples.
NextJs generating code in server side as you know.
This error means that something on the server is different from the Client. This can happen if the client does a re-render.
For example.
export default function Test(props) {
return (
<>
<span>{props.name}</span>
</>
);
}
I have this simple Test component.And I send name (1) prop from another component to this Test component. And if I change this name (to 2) in client using redux (for example I have another name in my redux store) after page generated I get this error.
props did not match server "1" client "2"
To solve this error I need to just not change this name with redux after page generated in server. The data can be change only with user manipulations after page rendered in server.
Same thing happened to me when I use Tabs from react-bootstrap. Koushik Saha's answer can be apply for that also but with a small change. Need to put react-bootstrap instead react-tabs
const Tabs = dynamic(import('react-bootstrap').then(mod => mod.Tabs), { ssr: false })
In case you miss it
If you are using Nextjs + Material-ui, there are actually custom codes that you can/need to include in your _document.js and _app.js to remove the server-side injected CSS so the CSS is recreated when page loads.
As codes changes with mui's and nextjs' version, i will refer you to the repository directly
https://github.com/mui-org/material-ui/tree/master/examples/nextjs/pages
As per the documentation in the react-tabs repo/npmjs.org page (https://www.npmjs.com/package/react-tabs):
import { resetIdCounter } from 'react-tabs';
resetIdCounter();
ReactDOMServer.renderToString(...);
I was having the same issue and called the resetIdCounter function inside my parent component to the tabs structure and cleared up the error.
Not sure if maybe there is a better place to use this function, like maybe in a useEffect hook or something, but I'm going with this for now.

Reactjs component - one vs many

I'm new to react and I'm trying to figure out the best way to make a component that can handle different scenarios. I'm not sure if the best practice would be to make multiple components or one component to handle it all.
Imagine a frontpage were you have 3 different entrances like recent products, blogpost or Instagram pictured. Each entrance use a component called featured and inside that component I should render either products, blogpost or Instagram pictures. Everything for the layout is the same, its just the items in the grid that needs to change. What would be the best way to solve this? one component with 3 different sub-components or 3 components with one for each type.
I know how to make 3 different components, but I'm not sure how to make one component to handle subcomponents.
This could be the component and the "grid-item--product" could also be a "grid-item--blogpost or "grid-item--Instagram" - "grid" could also be a "two-col" or "three-col".
<div className="featured">
<div className="featured--content">
<div className="grid four-col">
<grid-item--product />
</div>
</div>
</div>
and this could be where I would call the component and hopefully be able to handle which component should be rendered inside and what the grid should be for this feature.
<div className="frontpage-route">
<h2>Frontpage Route</h2>
<Featured />
</div>
Can you help me? I would love an example if possible.
Thanks.
It sounds like what you want is the children prop. You can add the children prop to Featured and just pass the correct children to it. See an example here:
const Featured = ({ children, numColumns = "one" }) => (
<div className="featured">
<div className="featured--content">
<div className={`grid ${numColumns}-col`}>
{children}
</div>
</div>
</div>
)
const App = () => (
<div className="frontpage-route">
<h1>Frontpage Route</h1>
<h2>Products</h2>
<Featured numColumns="two">
<grid-item--product />
<grid-item--product />
</Featured>
<h2>Blogs</h2>
<Featured numColumns="three">
<grid-item--blog />
<grid-item--blog />
</Featured>
<h2>Instagram</h2>
<Featured>
<grid-item--instagram />
<grid-item--instagram />
</Featured>
</div>
)
You can use consitional rendering and three boolean variables to display components.
e.g:
<div className="featured">
<div className="featured--content">
<div className="grid four-col">
{product && <grid-item--product />} //if product var is true this component renders
{blogpost && <grid-item--blogpost />} //if blogpost var is true this component renders
{instagram && <grid-item--instagram />} //if instagram var is true this component renders
</div>
</div>
</div>

React Router not loading specific component and removing all other components too

I'm learning the basics of React Router. So what I'm making right now has a navigation bar on top and two buttons below this top bar. What I want is for the a table or something of the sort to show up when I press one of the buttons.
The problem is that when I click the button, the URL changes but the all the components vanish. Even the component I want displayed doesn't show and the other components (which ideally should stay) also disappear.
What am I doing wrong here? The code is as follows :-
const Site = () =>
<React.Fragment>
<div className="container-fluid row">
<div className="offset-3 col-sm-4">
<Link to="/A">
<Button value="A"/>
</Link>
</div>
<div className="col-sm-4">
<Link to="/B">
<Button value="B"/>
</Link>
</div>
</div>
<div>
<Route path="/B" component={B}/>
</div>
</React.Fragment>
export default Site;
The Site page has the URL '/Site'.
Edit:
Just thought I'd mention the structure a bit. So for now I have a page with a button. Clicking this button should load the a component (called Base with URL '/Site') which is calling the TopBar and Site components.
Then I have these two buttons - A and B which have their respective URLs.

Why return multiple elements in React is not allowed?

it can only return only one element tag in render.
In v16, we can render multiple elements by using an array.
so why cannot straightly write mutiple element tags in React?
render(){
return(
<div />
<div />
)
}
I mean that why cannot render multiple elements but not how to render mutiple elements.
React implementation relies on constructing a tree like structure which it uses to for reconcilation. When you return multiple elements from React elements from the render method, the assumtion that the tree will have one root node for the Component will not longer hold, hence making it difficult to process reconcilation algorithm.
Thus react gives you a limitation to provide a root node. If you return an array of elements from v16 onwards, react will internally create a dummy node as the parent.
From version 16.2 onwards React provides a React.Fragment component, that provides a cleaner syntax to return multiple elements
render(){
return(
<React.Fragment>
<div />
<div />
</React.Fragment>
)
}
React needs a parent element to render anything. You could put them in an array, or use a tool they gave for this exact purpose, the fragment component.
A fragment is just an empty node that won't show in the DOM allowing you to return multiple JSX components next to each other :
render(){
return(
<>
<div />
<div />
</>
)
}
If your linter is not a fan of this, you can use React.Fragment instead :
render(){
return(
<React.Fragment>
<div />
<div />
</React.Fragment>
)
}
The short answer to your question is... well this is just how React works and how their rendering engine is designed.
For now, multiple elements put together will not be interpreted as an array.
You can try
render(){
return[
<div> Div 1</div>,
<div> Div 2</div>,
<div> Div 3</div>,
<div> Div 4</div>
]
}

How to re-use HTML component wrapper in a sequence of child components?

I have what I thought would be a very simple question about reusing html wrappers for components. But I'm not sure what the 'proper' way to do it is.
I want to render a series of components reusing the same (complex) html wrapper for each of them. Then rendering the a set of different child components inside that wrapper.
(render 10 of these:)
<div i start>
<div start reusable wrapper>
<child component - one of ten different components, one after the other>
<div end reusable wrapper
<div i end>
I just need a high level suggestion. I feel like everything I think of is 'hacking it'.
const Layout = props => (
<div whateverattributes>
<div whateverotherattributes>
{props.children}
</div>
</div>
);
Then
<Layout>
<ChildComponent />
</Layout>

Resources