React JS Read props data only when I refresh the page

Viewed 484

I'm using React with functional components. When I log in I redirect the user to the Dashboard page using history.push('/dashboard'). When I do a console log on the Dashboard page it shows me all the data available in the props. But the data will not render on the page, it shows "Uncaught (in promise) TypeError: Cannot read property 'profile' of undefined". When I refresh the page or use { forceRefresh:true } in history everything works fine.

SideBar Component:

import React,{useEffect} from 'react';
import { Link,withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { userActions } from '../../../_actions/users'
import {
    Sidebar,
    UncontrolledButtonDropdown,
    Avatar,
    AvatarAddOn,
    DropdownToggle,
    DropdownMenu,
    DropdownItem
} from './../../../components';

function SidebarTopA(props) {
    const { authentication } = props
    function logout(){
        return (e)=>props.logout()
    }
    return (
        <React.Fragment>
            { /* START: Sidebar Default */}
            <Sidebar.HideSlim>
                <Sidebar.Section className="pt-0">
                    <Link to="/" className="d-block">
                        <Sidebar.HideSlim>
                            <Avatar.Image
                                size="lg"
                                src={authentication.user.user.profile.profile_photo}
                                addOns={[
                                    <AvatarAddOn.Icon
                                        className="fa fa-circle"
                                        color={authentication.loggedIn ? "success" :"warning"}
                                        key="avatar-icon-fg"
                                    />
                                ]}
                            />
                        </Sidebar.HideSlim>
                    </Link>

                    <UncontrolledButtonDropdown>
                        <DropdownToggle color="link" className="pl-0 pb-0 btn-profile sidebar__link">
           {authentication.user.user.first_name} {authentication.user.user.last_name}
                            <i className="fa fa-angle-down ml-2"></i>
                        </DropdownToggle>
                        <DropdownMenu persist>
                            <DropdownItem header>
                            {authentication.user.user.email}
                            </DropdownItem>
                            <DropdownItem divider />
                            <DropdownItem tag={Link} to="/apps/profile-details">
                                <i className="fa fa-fw fa-user mr-2"></i>
                    Your Profile
                    </DropdownItem>
                            <DropdownItem divider />
                            <DropdownItem tag={Link} to="/" onClick={logout()}>
                                <i className="fa fa-fw fa-sign-out mr-2"></i>
                        Sign Out
                    </DropdownItem>
                        </DropdownMenu>
                    </UncontrolledButtonDropdown>
                    <div className="small sidebar__link--muted">
                    {authentication.user.user.profile.job_title}
                    </div>
                </Sidebar.Section>
            </Sidebar.HideSlim>
            { /* END: Sidebar Default */}

            { /* START: Sidebar Slim */}
            <Sidebar.ShowSlim>
                <Sidebar.Section>
                    <Avatar.Image
                        size="sm"
                        src={authentication.user.user.profile.profile_photo} 
                        addOns={[
                            <AvatarAddOn.Icon
                                className="fa fa-circle"
                                color="white"
                                key="avatar-icon-bg"
                            />,
                            <AvatarAddOn.Icon
                                className="fa fa-circle"
                                color="success"
                                key="avatar-icon-fg"
                            />
                        ]}
                    />
                </Sidebar.Section>
            </Sidebar.ShowSlim>
            { /* END: Sidebar Slim */}
        </React.Fragment>

    );

}

function mapState(state) {
    const { authentication } = state
    return { authentication };
}
const actionCreators = {
    logout: userActions.logout
}
const connectedHomePage = withRouter(connect(mapState, actionCreators)(SidebarTopA));
export { connectedHomePage as SidebarTopA };
2 Answers

It seems that the profile info is not available while rendering SidebarTopA.
I suggest you to safeguard it, and to get rid of forceRefresh.
Add this in SidebarTopA, above your existing return (and get rid of forceRefresh):

if(!authentication.user || !authentication.user.user || !authentication.user.user.profile){
    return "Loading user profile, please wait..."
}

Finally, I solve it by using redux-persist package.

My Store setup is:

import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { createLogger } from 'redux-logger';
import rootReducer from '../_reducers';
import { composeWithDevTools  } from 'redux-devtools-extension';
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
const persistConfig = {
    key: 'chedsk',
    storage,
  }
const loggerMiddleware = createLogger();

const persistedReducer = persistReducer(persistConfig, rootReducer)
 
const composeEnhancers = composeWithDevTools({trace: true, traceLimit: 20});
export const store = createStore(
    persistedReducer,composeEnhancers( applyMiddleware(
        thunkMiddleware,
        loggerMiddleware
    ))
   
)
export const persistor = persistStore(store)

In App component I do.

import { store, persistor } from './_helpers/store';
import { PersistGate } from 'redux-persist/integration/react'
render(
    <Provider store={store}>
        <PersistGate loading={null} persistor={persistor}>
            <App />
        </PersistGate>
    </Provider>,
    document.querySelector('#root')
);
Related