Search code examples
reactjsreduxreact-redux

Redux state not dispatched on page load


I can't find the reason why my redux state is not dispatched when the page loads, even if there is a dispatch event when the Component mounts

Here is a basic example of my problem:

export const SET_SITE_NAME = "SET_SITE_NAME";

Actions:

import {SET_SITE_NAME} from "./AppBarTypes";

export const setSiteName = (state) => dispatch => {
    dispatch({
        type: SET_SITE_NAME,
        payload: state
    })
}

Reducer:

import {SET_SITE_NAME} from "./AppBarTypes";

const initialState = {
    state: "Dashboard"
}

export const appBarReducer = (state = initialState, action) => {
    switch(action.type) {
        case SET_SITE_NAME:
            return {
                ...state,
                state: action.payload
            };
        default:
            return state;
    }
}

Basic usage:

function ProjectsList(props) {
   
    useEffect(() => {
        props.setSiteName("Projects");
    }, []);

    return (
        <Main open={props.drawer.state}>
        </Main>
    );
}

ProjectsList.propTypes = {
    setSiteName: PropTypes.func.isRequired
};

const mapStateToProps = state => ({
    projects: state.projects,
    drawer: state.drawer
});

export default connect(mapStateToProps, {
    getProjects,
    setSiteName
})(withRouter(ProjectsList));

From what I was able to debug, the setSiteName function runs and it always receives the correct state. Also, if I navigate to other Component on the site and back to this Component, it loads the state perfectly, so I assume the implementation is correct.

Edit

I have created a working example where I was able to trace back the problem. https://stackblitz.com/edit/react-sf1fmj?file=src%2FApp.js

The problem is related to useMediaQuery. As you can see in the example, if you uncomment that part, the default redux state 'Dashboard' will be shown instead of the 'Projects' state which is set.

Though I don't know why this causes this problem and how I could solve it. As you can see, in this example I don't even use that value, just query it...


Solution

  • I needed to change this:

    const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
    

    to this:

    const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)', { noSsr: true });
    

    Metarial UI useMediaQuery hooks render twice to React Component, do you have any solution for it?

    According to docs, you can set this to false if you are not doing any server side rendering:

    Options.noSsr (Boolean [optional]): Defaults to false. In order to perform the server-side rendering reconciliation, it needs to render twice. A first time with nothing and a second time with the children. This double pass rendering cycle comes with a drawback. It's slower. You can set this flag to true if you are not doing server-side rendering.