Search code examples
reactjsreduxredux-thunkdispatchthunk

Why is my dispatch/console.log not firing when I call the action?


I was working on my final project for Flatiron and I came across a bug while working on my frontend. I tried many things, but always came back to this one issue. My callback function inside my dispatch is not firing. So while I may be interested to know whether my code should be refactored/fixed of bugs, the biggest problem is that I cannot run my dispatches through an action. Here is my generic container:

import { useEffect } from "react"
import { connect } from "react-redux"

import * as actions from "../../actions/index"
import Component from "./Component"


const Container = (props) => {
  useEffect(() => {
    actions.menuItemsFetchRandom(8)
  }, [])
  const menuItemComponents = props.menuItems.menuItems.map((menuItem) => {
    return (
      <Component key={menuItem.key} menuItem={menuItem} />
    )
  })
  return (
    <div className="container">
      {
        props.menuItems.fetching
        ? "loading..."
        : (
          props.menuItems.error === ""
          ? menuItemComponents
          : props.menuItems.error
        )
      }
    </div>
  )
}

const mapStateToProps = (state) => {
  return {
    menuItems: state.menuItems
  }
}

export default connect(mapStateToProps)(Container)

And my actions.menuItemsFetchRandom() comes from /actions/menuItems.js:

import * as common from "./common"
import * as reducers from "../reducers/index"

const MENU_ITEMS_URL = common.API_URL + "menu_items/"

export const menuItemsFetchMany = (options) => {
  return (dispatch) => {
    dispatch({
      type: reducers.MENU_ITEMS_FETCH_REQUEST
    })
    fetch(MENU_ITEMS_URL + options).then((response) => {
      return response.json()
    }).then((menuItems) => {
      dispatch({
        type: reducers.MENU_ITEMS_FETCH_SUCCESS,
        payload: menuItems
      })
    }).catch((error) => {
      dispatch({
        type: reducers.MENU_ITEMS_FETCH_ERROR,
        payload: error
      })
    })
  }
}

export const menuItemsFetchRandom = (numberOfItems) => {
  console.log("hi")
  return (dispatch) => {
    console.log("Hello")
    dispatch({
      type: reducers.MENU_ITEMS_FETCH_REQUEST
    })
    fetch(MENU_ITEMS_URL).then((response) => {
      return response.json()
    }).then((menuItems) => {
      const length = menuItems.length
      if (numberOfItems > length) {
        numberOfItems = length
      }
      dispatch({
        type: reducers.MENU_ITEMS_FETCH_SUCCESS,
        payload: (() => {
          const result = []
          while (result.length !== length) {
            const choice = menuItems[common.getRandomInt(length)]
            if (result.includes(choice)) {
              continue
            }
            result.push(choice)
          }
        })()
      })
    }).catch((error) => {
      dispatch({
        type: reducers.MENU_ITEMS_FETCH_ERROR,
        payload: error
      })
    })
  }
}

My /reducers/menuItems.js looks like this:

export const MENU_ITEMS_FETCH_REQUEST = "MENU_ITEMS_FETCH_REQUEST"
export const MENU_ITEMS_FETCH_SUCCESS = "MENU_ITEMS_FETCH_SUCCESS"
export const MENU_ITEMS_FETCH_ERROR = "MENU_ITEMS_FETCH_ERROR"

const initialState = {
  menuItems: [],
  error: "",
  fetching: false
}

const menuItems = (state=initialState, action) => {
  switch (action.type) {
    case MENU_ITEMS_FETCH_REQUEST: {
      return {
        ...state,
        error: "",
        fetching: true
      }
    }
    case MENU_ITEMS_FETCH_SUCCESS: {
      return {
        ...state,
        menuItems: action.payload,
        error: "",
        fetching: false
      }
    }
    case MENU_ITEMS_FETCH_ERROR: {
      return {
        ...state,
        error: action.payload,
        fetching: false
      }
    }
    default: {
      return state
    }
  }
}

export default menuItems

But that doesn't seem to matter as the console.log inside the callback function in menuItemsFetchRandom() does not fire. I get the console.log("hi"), but not the console.log("Hello"). Which to me tells me its either something wrong with my code, or something wrong with redux-thunk.


Solution

  • You need to actually dispatch that action, not just call the action creator.

      const dispatch = useDispatch();
      useEffect(() => {
        dispatch(actions.menuItemsFetchRandom(8))
      }, [])
    

    PS: also, there is no need to use connect in function components. Using useSelector and useDispatch is much easier and the official recommendation. Additionally, you are writing a pretty outdated style of redux that makes you write a multitude of the code that is required with modern redux. You are likely following very outdated tutorials. Please see the official tutorials at https://redux.js.org/tutorials/index