ruby-on-railsreduxreact-hooksuse-effectdispatch-async

React/Redux with hooks to fetch from Rails API


I am trying to use redux and hooks with my rails / react application and running into a weird problem. When I first console log my list object that is being fetched, they display fine in the console and render correctly See this picture

Here is my code for my Lists.js

 export default function Lists() {
  const lists = useSelector(state => state);
  const dispatch = useDispatch()

  useEffect(() => {
    dispatch(fetchLists())
  }, [])

console.log(lists)

      return (
      <div>
        <h2>Your Lists</h2>
        {lists && lists.map(list => {
          return <List list={list} key={list.id}/>
        })}
      </div>
      )
}

Then as soon as I write something else or refresh the page I am getting this error that map is not defined - even though clearly lists is an array of objects that should be able to be mapped over. See this picture

Here is my reducer:

import { GET_LISTS } from "../constants"

export default function listReducer(state = {lists: []}, action){
    switch(action.type) {
        case GET_LISTS:
            return {
                ...state,
                lists: action.payload
            }

        default: 
            return state
    }
}

and my action:

export function fetchLists(){
    return (dispatch) => {
        fetch("http://localhost:3000/api/v1/lists")
          .then((res) => res.json())
          .then((lists) => dispatch({ type: GET_LISTS, payload: lists }));
   

} }

So basically when I comment out the code with .map lists gets console.logged correctly, then I comment it in it renders the lists fine, and as soon I as I refresh the page I am getting this errer. Very confusing and I have no idea what else to try.

So far I have tried:

Basically no matter what I try I am still getting the

Lists.js:32 Uncaught TypeError: lists.map is not a function

error on a refresh.

It also puts me in a debugger when there is no debuggers in my app. Does anyone know what I am missing?


Solution

  • This happens because you try to map() an object rather than an array. See short example of the problem here:
    enter image description here
    When all is set, you probably use the initial value as array. that's why it works []. But when you update the variable lists becomes an object {[]}, which is unmappable.
    You could check if the lists not only exists, but also is the type you want it to be. Here are some answers for the checking process: How do you check if a variable is an array in JavaScript.

    Here is the sandbox to reproduce the error you have and handle it without exception appearing using conditional rendering of the DOM:
    Sandbox
    Sample code to check if the type is array with useEffect():

    useEffect(() => {
      console.log("is array type? : ", Array.isArray(lists));
    }, [lists]);