Can I use a react HOC in this way without future pitfalls

Viewed 111

I learn ReactJs and have a design Composition question about ReactJs higher order component (HOC).

In the code below App.jsx I use this withAuthentication HOC that initializes app core processes. This HOC value is not used in the App.js. Therefore I must suppress all withAuthentication HOC render callbaks and I do that in the shouldComponentUpdate by returning false.

(I use this HOC in many other places to the get HOC's value but not in App.jsx)

File App.jsx:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { compose } from 'recompose';
import { getAlbumData } from './redux/albumData/albumData.actions';
import { getMetaData } from './redux/albumMetaData/albumMetaData.actions';

import Header from './components/structure/Header';
import Content from './components/structure/Content';
import Footer from './components/structure/Footer';
import { withAuthentication } from './session';
import './styles/index.css';

class App extends Component {
    componentDidMount() {
        const { getMeta, getAlbum } = this.props;
        getMeta();
        getAlbum();
    }

    shouldComponentUpdate() {
        // suppress render for now boilerplate, since withAuthentication
        // wrapper is only used for initialization. App don't need the value
        return false;
    }

    render() {
        return (
            <div>
                <Header />
                <Content />
                <Footer />
            </div>
        );
    }
}
const mapDispatchToProps = dispatch => ({
    getMeta: () => dispatch(getMetaData()),
    getAlbum: () => dispatch(getAlbumData()),
});

export default compose(connect(null, mapDispatchToProps), withAuthentication)(App);

The HOC rwapper WithAuthentication below is a standard HOC that render Component(App) when changes are made to Firebase user Document, like user-role changes, user auth-state changes..

File WithAuthentication .jsx

   import React from 'react';
    import { connect } from 'react-redux';
    import { compose } from 'recompose';
    import AuthUserContext from './context';
    import { withFirebase } from '../firebase';
    import * as ROLES from '../constants/roles';
    import { setCurrentUser, startUserListener } from '../redux/userData/user.actions';
    import { selectUserSlice } from '../redux/userData/user.selectors';
    
    const WithAuthentication = Component => {
        class withAuthentication extends React.Component {
            constructor() {
                super();
                this.state = {
                    authUser: JSON.parse(localStorage.getItem('authUser')),
                };
            }
    
            componentDidMount() {
                const { firebase, setUser, startUserListen } = this.props;
                this.authListener = firebase.onAuthUserListener(
                    authUser => {
                        this.setState({ authUser });
                        setUser(authUser);
                        startUserListen();
                    },
                    () => {
                        localStorage.removeItem('authUser');
                        this.setState({ authUser: null });
                        const roles = [];
                        roles.push(ROLES.ANON);
                        firebase
                            .doSignInAnonymously()
                            .then(authUser => {
                                if (process.env.NODE_ENV !== 'production')
                                    console.log(`Sucessfully signed in to Firebase Anonymously with UID: ${firebase.getCurrentUserUid()}`);
                                firebase.doLogEvent('login', { method: 'Anonymous' });
                                firebase
                                    .userDoc(authUser.user.uid)
                                    .set({
                                        displayName: `User-${authUser.user.uid.substring(0, 6)}`,
                                        roles,
                                        date: firebase.fieldValue.serverTimestamp(),
                                    })
                                    .then(() => {
                                        console.log('New user saved to Firestore!');
                                    })
                                    .catch(error => {
                                        console.log(`Could not save user to Firestore! ${error.code}`);
                                    });
                            })
                            .catch(error => {
                                console.error(`Failed to sign in to Firebase: ${error.code} - ${error.message}`);
                            });
                    },
                );
            }
    
            componentWillUnmount() {
                this.authListener();
            }
    
            render() {
                const { currentUser } = this.props;
                let { authUser } = this.state;
                // ALl changes to user object will trigger an update
                if (currentUser) authUser = currentUser;
                return (
                    <AuthUserContext.Provider value={authUser}>
                        <Component {...this.props} />
                    </AuthUserContext.Provider>
                );
            }
        }
    
        withAuthentication.whyDidYouRender = true;
    
        const mapDispatchToProps = dispatch => ({
            setUser: authUser => dispatch(setCurrentUser(authUser)),
            startUserListen: () => dispatch(startUserListener()),
        });
    
        const mapStateToProps = state => {
            return {
                currentUser: selectUserSlice(state),
            };
        };
    
        return compose(connect(mapStateToProps, mapDispatchToProps), withFirebase)(withAuthentication);
    };
    
    export default WithAuthentication;

My question is will this hit me later with problems or is this ok to do it like this?

I know a HOC is not suppose to be used like this. The WithAuthentication is taking care of Authentication against Firebase and then render on all user object changes both local and from Firestore listener snapshot.

This HOC is used in many other places correctly but App.jsx only need to initialize the HOC and never use it's service.

My question is will this hit me later with problems or is this ok to do it like this?

0 Answers
Related