Search code examples
javascriptreactjsfirebasereduxfirebase-authentication

Why is the Payload Null in My Redux Action?


I am working on a React project using Redux (not Redux Toolkit) and facing an issue where the payload in my Redux action is null. I’m using Firebase for authentication, and I’m trying to dispatch the setCurrentUser action with the user information, but it seems to be resulting in a null payload.

// Action creator
export const setCurrentUser = user => ({
    type: 'SET_CURRENT_USER',
    payload: user,
});

// User reducer
const INITIAL_STATE = {
    currentUser: null,
};

const userReducer = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case 'SET_CURRENT_USER':
            return {
                ...state,
                currentUser: action.payload,
            };
        default:
            return state;
    }
};

// App component
class App extends React.Component {
    unsubscribeFromAuth = null;
    unsubscribeFromSnapshot = null;

    componentDidMount() {
        const { setCurrentUser } = this.props;

        this.unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
            if (userAuth) {
                const userRef = await createUserProfileDocument(userAuth);

                this.unsubscribeFromSnapshot = onSnapshot(userRef, snapShot => {
                    setCurrentUser({
                        id: snapShot.id,
                        ...snapShot.data(),
                    });
                });
            } else {
                setCurrentUser(null); // This might be causing the null payload
            }
        });
    }

    componentWillUnmount() {
        if (this.unsubscribeFromAuth) this.unsubscribeFromAuth();
        if (this.unsubscribeFromSnapshot) this.unsubscribeFromSnapshot();
    }

    render() {
        return (
            <div>
                <Header />
                <Routes>
                    <Route path="/" element={<HomePage />} />
                    <Route path="/shop" element={<ShopPage />} />
                    <Route path="/signin" element={<SignInAndSignUpPage />} />
                </Routes>
            </div>
        );
    }
}

const mapDispatchToProps = dispatch => ({
    setCurrentUser: user => dispatch(setCurrentUser(user)),
});

When I check the action dispatched, the payload is null

{type: 'SET_CURRENT_USER', payload: null}

I set up Firebase authentication in my React app and dispatched a Redux action to set the current user.I expected the action to dispatch the user’s information upon successful login.


Solution

  • You've already identified the line of code that causes the behavior:

    setCurrentUser(null); // This might be causing the null payload
    

    When a page first loads, onAuthStateChanged calls your function with a null user object, which means your code is going call setCurrentUser(null). Even if the user previously signed in, that user is not known immediately on a newly page load. It takes some time until Firebase is able to validate their auth token, and auth state observer gets a real user object to work with. Your app should probably show some sort of loading indicator until the user object is available.

    I suggest adding some logging so you can observe how this works more easily for yourself.

    See also: