My components are not rendering on "Link" clicks but the url route does change, and if I manually refresh the browser the correct page renders. I have a private route created for the '/' path that uses a redirect if the user is not authenticated and send them back to the login. I have had a similar app working before almost set up identically but with using context instead of redux. I have read that react-router-dom and redux don't exactly pair well together but I don't fully understand why, I tried linking it up to the npm package "History" but saw multiple ways it can be done and couldn't successfully make it work. I can provide any additional code/information needed. Big thanks in advance to anyone that can assist. Also here is a link to the full repo: https://github.com/AustinRobinsonDev/license
I should add I had withRouter() on my main components and it was changing the url but not the component and I removed withRouter() and it doesn't change the URL or component
Versions:
- react-router-dom 5.2.0
- react-dom 18.0.0
- redux 4.1.2
index.js:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
reportWebVitals();
here is my main app.js:
const App = () => {
return (
<Provider store={store}>
<Router>
<>
<Navbar />
<Switch>
<Route exact path='/about' component={About} />
<Route exact path='/register' component={Register} />
<Route exact path='/login' component={Login} />
<PrivateRoute exact path='/' component={Home} />
</Switch>
</>
</Router>
</Provider>
);
}
export default App;
Navbar with the router Links:
const Navbar = ({auth, logout, clearLicense}) => {
const onLogout = () => {
logout();
clearLicense();
}
const authLinks = (
<>
<li>Hello {auth.user && auth.user.name}</li>
<li>
<a onClick={onLogout} href="#!">
<span className="hide-sm">Logout</span>
</a>
</li>
</>
)
const guestLinks = (
<>
<li>
<Link to='/register'>Register</Link>
</li>
<li>
<Link to="/login">Login</Link>
</li>
</>
)
return (
<div className='navbar bg-primary'>
<h1>License Manager{' '}Icon</h1>
<ul>
{auth.isAuthenticated ? authLinks : guestLinks}
</ul>
</div>
)
}
const mapStateToProps = state => ({
auth: state.auth
});
export default connect(mapStateToProps, { logout, clearLicense })(Navbar);
and an example of a component that will not re render:
const Login = ({history, auth, setAlert, login}) => {
useEffect(() => {
if (auth.isAuthenticated) {
history.push('/');
}
if (auth.error === 'Invalid Credentials') {
console.log('error invalid credentials')
setAlert(auth.error, 'danger');
clearErrors();
}
// eslint-disable-next-line
}, [auth.error, auth.isAuthenticated, history]);
const [user, setUser] = useState({
email: '',
password: ''
});
const { email, password } = user;
const onChange = e => setUser({ ...user, [e.target.name]: e.target.value });
const onSubmit = e => {
console.log('onSubmit clicked')
e.preventDefault();
if (email === '' || password === '') {
setAlert('Please fill in all fields', 'danger');
} else {
login({
email,
password
})
}
};
return (
<div className='form-container'>
<h1>
Account <span className='text-primary'>Login</span>
</h1>
<form onSubmit={onSubmit}>
<div className='form-group'>
<label htmlFor='email'>Email Address</label>
<input
id='email'
type='email'
name='email'
value={email}
onChange={onChange}
required
/>
</div>
<div className='form-group'>
<label htmlFor='password'>Password</label>
<input
id='password'
type='password'
name='password'
value={password}
onChange={onChange}
required
/>
</div>
<input
type='submit'
value='Login'
className='btn btn-primary btn-block'
/>
</form>
</div>
);
};
const mapStateToProps = state => ({
auth: state.auth
});
export default connect(mapStateToProps, {setAlert, login})(Login);