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.
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