altF4
altF4

Reputation: 319

React renders before API call

So I make an API call to server to get the currentUser,

useEffect(() => {
    loadUser()
},[])

Since behaviour of React is like render first run lifecycle methods second, at first, my selector for user returns null which what I expect.

However I still got user is null error, so this is my code =>

const isAuthenticated = useSelector(state => state.auth.isAuthenticated)
const user = useSelector(state => state.auth.user)

const authLinks = (
    <nav className="auth-navbar">
        <div className="auth-navbar__dropdown">
            <button type="button" className="dropdown-btn" onClick={dropdown}><img src={profilephoto}></img></button>
            <div className="dropdown-menu">
                <Link to={`u/${user.username}`} className="dropdown-link">Profile</Link>
                <Link to="/settings" className="dropdown-link">Settings</Link>
                <Link to="/" onClick={onClickHandler} className="dropdown-link">Logout</Link>
            </div>
        </div>
    </nav>
)
if (user) {
    return (
        <header className="header">
            <Link to="/" className="logo" >
                <img src={logo} alt="logo"/>
            </Link>
            {isAuthenticated ? authLinks : guestLinks}
        </header>
    )
} else {
    return <p>loading..</p>
}

Questions like this have been asked before on stackoverflow but solutions are similar to mine and it still doesn't work. Please help me.

P.S: the default of user is null in the reducer.

EDIT: The action creator to load user =>

export const loadUser = () => (dispatch) => {

    dispatch({ type: USER_LOADING })

    const config = {
        withCredentials: true
    }

    axios.get('http://127.0.0.1:8000/auth/user/', config)
        .then(res => {
            dispatch({
                type: USER_LOADED,
                payload: res.data
            })
        }).catch(err => {
            console.log(err)
            dispatch({
                type: AUTH_ERROR
            })
        })
}

Normally user loads without error =>

user

reducer =>

const initialState = {
    isAuthenticated: false,
    isLoading: false,
    user: null,
}
export default function(state=initialState, action){
    switch(action.type){
        case USER_LOADING:
            return {
                ...state,
                isLoading: true
            }
        case USER_LOADED:
            return {
                ...state,
                isAuthenticated: true,
                isLoading: false,
                user: action.payload
            } 

Upvotes: 0

Views: 73

Answers (1)

lawrence-witt
lawrence-witt

Reputation: 9354

I think you need to make authLinks a function which executes and returns the relevant JSX only when user exists. As it is, the variable will try to access the property user.username before it has been initialised.

const authLinks = () => (
  ...
);

And then call it in the return.

{isAuthenticated ? authLinks() : guestLinks}

Upvotes: 1

Related Questions