Trigger Redux Action from Gatsby Browser API?

Viewed 292

How do I trigger a redux action from within onRouteUpdate gatsby-browser.js API.

I have a TOGGLE_MENU action that needs to be set to false when a user successfully navigates to a new page, to close the menu on mobile/tablet.

I'm using the gatsby-plugin-react-redux plugin.

Current implementation here: https://dev.poshwash.london

I tried adding store.dispatch(toggleMenu(false)) but it didn't work.

src/state/app.js
const initialState = {
  isMenuOpen: false,
  scrollY: 0,
}

const TOGGLE_MENU = "TOGGLE_MENU"
export const toggleMenu = isOpen => ({ type: TOGGLE_MENU, payload: isOpen })

export default (state = initialState, action) => {
  const { type, payload } = action
  switch (type) {
    case TOGGLE_MENU: {
      const scrollY = payload ? window.scrollY : state.scrollY

      return { ...state, isMenuOpen: payload, scrollY }
    }
    default: {
      return state
    }
  }
}
src/state/createStore.js
import { createStore } from "redux"
import { composeWithDevTools } from "redux-devtools-extension"
import rootReducer from "."

// preloadedState will be passed in by the plugin
export default preloadedState => {
  return createStore(rootReducer, preloadedState, composeWithDevTools())
}
gatsby-browser.js
/**
 * Implement Gatsby's Browser APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/browser-apis/
 */

import { toggleMenu } from "./src/state/app"
import store from "./src/state/createStore"

export const onRouteUpdate = ({ location, prevLocation }) => {
  store.dispatch(toggleMenu(false))
  console.log("new pathname", location)
  console.log("old pathname", prevLocation)
}
2 Answers

I've just had a similar problem and managed to find a solution. Just an advice for the people with similar problem in the future. You need to change your src/state/createStore.js file like this.

    import { createStore } from "redux"
    import { composeWithDevTools } from "redux-devtools-extension"
    import rootReducer from "."
    
    // After that you will need 
    // to import and use dispatch
    // on this variable
    // and import it like this: 
    // import { store } from "./src/state/createStore"
    export let store;
    
    // preloadedState will be passed in by the plugin
    export default preloadedState => {
      store = createStore(rootReducer, preloadedState, composeWithDevTools());
      return store;
    }

Just export a function from your the JS file where you are storing your Provider, and then call it on gatsby-broswer.js onRouteUpdate function

ReduxWrapper.js

import React from 'react'
import { Provider } from 'react-redux'
import { ACTION } from './store/actions'
import {store} from './configureStore'



export const OnRouteChange = () => {
    store.dispatch(ACTION())
}

    export default ({ element, ...rest }) => {
        return (
        <Provider store={store}>
            {element}
        </Provider>
    )};

gatsby-browser.js

import { OnRouteChange } from './src/store/ReduxWrapper' 
export { default as wrapRootElement } from './src/store/ReduxWrapper'


export const onRouteUpdate = ({ location, prevLocation }) => {
  //call your function that you exported from provider
  console.log('Changing route here')
  OnRouteChange()
}
Related