I have a react/grqphql app and on the local host it works find but on heroku, if I login in or create a user it reloads the home page and in the menu I see the first name of the logged in user. If I click that link it takes me to the profile page, but if I am logged in and manually enter domain/profile I get a error saying cannot get /profile.
Even on the other links in the nav bar. The Events page, for example does not exist yet but if I click on Events in the navbar it will load a blank page with just the header and footer, but if I enter /events after the domain I get a page with nothing but Cannot GET /events.
Here is my index.js:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Here is my App.js:
import { Route, Routes, BrowserRouter as Router } from 'react-router-dom';
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
createHttpLink,
} from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import Container from 'react-bootstrap/Container';
import Header from './components/Header';
import Footer from './components/Footer';
import Home from './pages/Home';
import Profile from './pages/Profile';
//Construct our main GraphQL API endpoint
const httpLink = createHttpLink({
uri: '/graphql',
});
// Construct request middleware that will attach the JWT token to every request as an `authorization` header
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem('token');
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `${token}` : '',
},
};
});
const client = new ApolloClient({
// Set up our client to execute the `authLink` middleware prior to making the request to our GraphQL API
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});
function App() {
return (
<ApolloProvider client={client}>
<Container>
<Router>
<Header />
<Routes>
<Route exact path='/' element={<Home />}>
Home
</Route>
<Route exact path='/profile' element={<Profile />}>
Profile
</Route>
</Routes>
<Footer />
</Router>
</Container>
</ApolloProvider>
);
}
export default App;
I tried doing the Rouotes i a single line:
<Route exact path='/' element={<Home />} />
But neither way has had any effect.
In case you need to see it, here is the navbar code:
<>
<Navbar expand='md' id='main-nav'>
<Container>
<Navbar.Brand as={Link} to='/'>
<img src={logo} alt='TMH Logo' />
</Navbar.Brand>
<Navbar.Toggle
aria-controls='basic-navbar-nav'
className='custom-toggler'
/>
<Navbar.Collapse id='basic-navbar-nav'>
<Nav className='ps-4'>
<Nav.Item>
<Nav.Link as={NavLink} to='/'>
Home
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={NavLink} to='/events'>
Events
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={NavLink} to='/features'>
Features
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={NavLink} to='/clubs'>
Clubs
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={NavLink} to='/pricing'>
Pricing
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={NavLink} to='/about'>
Aboout
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={NavLink} to='/contact'>
Contact
</Nav.Link>
</Nav.Item>
{token ? (
<>
<Nav.Item>
<Nav.Link as={NavLink} to='/profile'>
{me.firstName}
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link onClick={handleLogout}>Logout</Nav.Link>
</Nav.Item>
</>
) : (
<Nav.Item>
<Nav.Link onClick={handleShow}>Signup/Login</Nav.Link>
</Nav.Item>
)}
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
</>
CodePudding user response:
This is because your server needs to support HTML5 push state. When you navigate by clicking a link that's using the HTML5 history
API (which react-router uses under the hood), its only changing the URL in the address bar -- it doesnt actually try to fetch that page from the server. However when you refresh or hit the URL from the outside of the site, the browser will simply try to load that URL from the server -- there is no client side code even loaded to use the history
API.
Your server needs a wildcard route configured such that any and all paths serve your index.html
. Then, your JS etc will load, read from the URL, and display the desired page.
If it's an express server you'd need something like this -- but the exact details really depend on your server technology and setup:
app.get('*', function(request, response) {
response.sendfile(__dirname '/public/index.html');
});