Reputation: 33
I built a HOC to use on protected routes in my app. It takes in the component that should be rendered at the route, checks if the user is authenticated, and then renders that component if they are. It works, but it causes the component to mount/unmount several times (as many times as the render function in my app.js file is called).
routes from my app.js
<Switch>
<Route path='/groups/show/:id'
component={ RequireAuth(Group) } />
<Route path='/groups/create'
component={ RequireAuth(CreateGroup) } />
<Route path='/groups'
component={ RequireAuth(GroupsMenu) } />
<Route path='/tutorials/:id' component={ Tutorial } />
<Route path='/tutorials' component={ TutorialMenu } />
<Route path='/ranked' component={ RankedPlay } />
<Route path='/casual' component={ CasualPlay } />
<Route path='/offline' component={ OfflinePlay } />
<Route path='/signup' component={ Signup } />
<Route path='/' component={ Menu } />
</Switch>
require_auth.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { store } from '../../index';
import { AUTH_ERROR } from '../../actions';
import PropTypes from 'prop-types';
import Display from './display';
export default function(ComposedComponent) {
class Authentication extends Component {
static propTypes = {
history: PropTypes.object.isRequired
};
componentWillMount() {
const { history } = this.props;
const error = 'You must be logged in to do this. Please login';
if (!this.props.authenticated) {
store.dispatch({ type: AUTH_ERROR, payload: error });
history.push('/');
}
}
componentWillUpdate(nextProps) {
const { history } = this.props;
const error = 'You must be logged in to do this. Please login';
if (!nextProps.authenticated) {
store.dispatch({ type: AUTH_ERROR, payload: error });
history.push('/');
}
}
render() {
return (
<Display if={ this.props.authenticated } >
<ComposedComponent { ...this.props } />
</Display>
);
}
}
function mapStateToProps(state) {
return {
authenticated: state.auth.authenticated
};
}
return withRouter(connect(mapStateToProps)(Authentication));
}
If you remove RequireAuth() from any of the routes, the component only mounts once when you hit the route. But adding it causes the component to mount every time app.js render() fires. Is there a way I can set this up so the component only mounts once?
Upvotes: 3
Views: 7224
Reputation: 961
By calling RequireAuth(Component)
in render, you are decorating Component
with your HOC in every render call, making that each render returns a new Component each render.
You should decorate Group
, CreateGroup
and GroupsMenu
with RequireAuth
, before exporting them. Just as you would with react-redux
's connect
.
Upvotes: 9