cstmxyz
cstmxyz

Reputation: 43

.map is not a function (am I really not using an array here?)

I'm trying to learn some react hooks by practice and trying to change the state at the same time.

Here is what my useState hook looks like:

const [names, setNames] = useState([
    "James",
    "Jessica",
    "Roger",
    "Alfred"
])

I have used JSX to return the array items from "names" on the page as follows:

{names.map((name)=> {
        return <p>{name}</p>
})}

This seems to display everything just fine, suggesting that the map function works correctly on the array called names.

However, when I create a function to update the state using setNames, I get the error "TypeError: names.map is not a function"

Here is what the function looks like:

const addName = () => {
    setNames({
      names: [...names, "Jessica"]
    })
  }

I am just running this in an onClick event through a button in the app:

<button onClick={addName}>Add</button>

Sorry in advanced if this is novice but I can't seem to understand why I'm getting this error. I understand that .map can only be used on an array, however that's what I thought names was.. an array. Also it displays names when I use the .map function so I'm just confused by the error itself.

Thanks in advance for any help.

Upvotes: 0

Views: 79

Answers (2)

Nicholas Tower
Nicholas Tower

Reputation: 85161

setNames({
  names: [...names, "Jessica"]
})

This is changing your state to no longer be an array, but rather to be an object with a .names property on it. Only in class components do you need to pass in an object when setting state.

Instead, you should do the following:

setNames([...names, "Jessica");

One slight improvement you could do is to use the function version of setNames. This will make sure you're always using the most recent version of the state, and thus eliminate the possibility of some bugs when setting state multiple times:

const addName = () => {
  setNames(prev => {
    return [...prev, "Jessica"];
  });
}

Upvotes: 2

0stone0
0stone0

Reputation: 44202

You're using the old setState logic.

setNames accepts the new value as first param, not an object, to add a name, change the addName to the following:

const addName = () => {
    setNames([...names, "Jessica"]) 
}

Correct modification of state arrays in React.js

Working example:

const {useState} = React;

const SameSet = () => {
    const [names, setNames] = useState([
        "James",
        "Jessica",
        "Roger",
        "Alfred"
    ]);
    
    const addName = () => {
        setNames([...names, "Jessica"])
    }
    
    return (  
        <div>
            {names.map((name) => <p>{name}</p>)}
            <button onClick={addName}>Add</button>
        </div>
    )
}
ReactDOM.render(<SameSet />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Upvotes: 0

Related Questions