I am trying to construct/replicate an e-commerce website using React. When trying to launch the dev server, I noticed that I wasn't getting anything rendered on my screen. Using the React Dev tools extension confirmed as much. From past experiences, adding the links to the App.js file would probably solve this, however, I'd rather have the links in the Header component. I am trying to link the image such that when I click on the image, it will render the component without refreshing. I believe I have followed all the required steps as per the react-router-dom documentation, but I can't get the site to work if I include the tag.
I commented out a few sections as I initially thought I had implemented the ContextAPI incorrectly. Any help would be much appreciated.
Here's a snippet of my App.js file
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { Header, Home } from './components'
import './App.css'
function App() {
return (
<div className='app'>
<Header />
<Router>
<Routes>
<Route path='/' element={<Home />} />
</Routes>
</Router>
</div>
)
}
export default App
Here's the Home.jsx file:
import React from 'react'
import { Product } from '..'
import { heroLanding, products } from '../../constants'
import './Home.css'
const Home = () => {
return (
<div className='home'>
<img src={heroLanding} alt='Landing Page' className='home__image' />
<div className='home__row'>
{products.map(
(product, index) =>
index < 2 && (
<Product
key={product.id}
title={product.title}
rating={product.rating}
price={product.price}
image={product.image}
/>
)
)}
</div>
<div className='home__row'>
{products.map((product, index) =>
(index > 1) & (index < 5) ? (
<Product
key={product.id}
title={product.title}
rating={product.rating}
price={product.price}
image={product.image}
/>
) : null
)}
</div>
<div className='home__row'>
{products.map((product, index) =>
index > 4 ? (
<Product
key={product.id}
title={product.title}
rating={product.rating}
price={product.price}
image={product.image}
/>
) : null
)}
</div>
</div>
)
}
export default Home
Here's the Header.jsx file:
import React from 'react'
import { BsCart4 as BasketIcon, BsSearch as Search } from 'react-icons/bs'
import { Link } from 'react-router-dom'
import { logo } from '../../constants'
//import { useStateValue } from '../../contextAPI/StateProvider'
import './Header.css'
const Header = () => {
// const [{ basket, user }, dispatch] = useStateValue()
return (
<div className='header'>
<Link to='/'>
<img src={logo} alt='Amazon Logo' className='header__logo' />
</Link>
<div className='header__search'>
<input
className='header__search-input'
type='text'
placeholder='Search ...'
/>
<span className='header__searchIcon'>
<Search className='header__searchIcon-icon' />
</span>
</div>
<div className='header__nav'>
<div className='header__option'>
<span className='header__option-lineOne'>Hello User</span>
<span className='header__option-lineTwoe'>Sign In</span>
</div>
<div className='header__option'>
<span className='header__option-lineOne'>Returns</span>
<span className='header__option-lineTwoe'>& Orders</span>
</div>
<div className='header__option'>
<span className='header__option-lineOne'>Your</span>
<span className='header__option-lineTwo'>Prime</span>
</div>
<div className='header__option-basket'>
<BasketIcon />
<span className='header__option-lineTwo header__basketCount'>0</span>
</div>
</div>
</div>
)
}
export default Header
CodePudding user response:
You should put Router at the beginning of the return statement in App.js.
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { Header, Home } from './components'
import './App.css'
function App() {
return (
<Router>
<div className='app'>
<Header />
<Routes>
<Route path='/' element={<Home />} />
</Routes>
</div>
</Router>
)
}
export default App
CodePudding user response:
Issue
The issue with the code is that the header and links are rendered outside the router handling the routes. This means it's [Router
] not aware of any external navigation actions above it in the React tree.
function App() {
return (
<div className='app'>
<Header />
<Router> // <-- routing context isn't aware of external actions
<Routes>
<Route path='/' element={<Home />} />
</Routes>
</Router>
</div>
)
}
Since you are using react-router-dom@6
you should certainly have some errors in the console warning you that the Link
components have been rendered outside any routing context and to move them into one.
Solution
The Header
component (and links) need to be moved into a router so they receive a proper routing context. You need only one router per app also, so go through your code and remove any extraneous routers you may have. This is so all RRD components use the same single routing context.
function App() {
return (
<div className='app'>
<Router>
<Header /> // <-- move inside routing context
<Routes>
<Route path='/' element={<Home />} />
</Routes>
</Router>
</div>
)
}
In most cases you will want to push the Router
as high as possible in your application's ReactTree. It's common to wrap App
in the index.js file so anything App
is rendering will have the proper routing context available to it.
Example:
...
import { BrowserRouter as Router } from 'react-router-dom';
...
ReactDOM.render(
<StrictMode>
.... other context wrappers ....
<Router>
<App />
</Router>
.... other context wrappers ....
</StrictMode>,
rootElement
);