Reactjs 当我的日志显示所讨论的数据是数组时,为什么会说TypeError:users.map不是一个函数?

Reactjs 当我的日志显示所讨论的数据是数组时,为什么会说TypeError:users.map不是一个函数?,reactjs,Reactjs,我正在尝试使用fetch执行POST请求,我的代码确实成功地发出了POST请求。但是,一旦react尝试在post请求后重新提交(我调用setUsers以更新状态),它就会错误地告诉我用户。map不是一个函数。我只是不明白为什么b/c我甚至采取措施先在一个新变量中复制状态,然后将新项推到该变量上,最后将该变量传递给setter中的用户。这是我的密码 const-App=()=>{ const[users,setUsers]=useState([]); 常量[formData,setFormDa

我正在尝试使用fetch执行POST请求,我的代码确实成功地发出了POST请求。但是,一旦react尝试在post请求后重新提交(我调用setUsers以更新状态),它就会错误地告诉我
用户。map
不是一个函数。我只是不明白为什么b/c我甚至采取措施先在一个新变量中复制状态,然后将新项推到该变量上,最后将该变量传递给setter中的用户。这是我的密码

const-App=()=>{
const[users,setUsers]=useState([]);
常量[formData,setFormData]=useState(
{
id:Math.round(Math.random()*1000000),
姓名:“,
年龄:“,
},
[用户]
);
useffect(()=>{
取回(“http://localhost:4000/")
.然后((res)=>res.json())
。然后((res)=>setUsers(res))
.catch((err)=>console.log(err));
}, []);
常量handleSubmit=(e)=>{
e、 预防默认值();
取回(“http://localhost:4000/", {
方法:“张贴”,
标题:{
“内容类型”:“应用程序/json”,
},
正文:JSON.stringify(formData),
})
。然后((res)=>{
res.json().then((数据)=>{
const newUsersList=用户;
newUsersList.push(数据);
console.log(newUsersList);
设置用户(()=>{
返回{
新用户列表,
};
});
});
})
.catch((err)=>console.log(err));
};
常量handleInput=(e)=>{
setFormData({…formData,[e.target.name]:e.target.value});
};
返回(
用户名
年龄
创建用户
    {users.map((用户)=>{ 返回
  • {user.name}
  • ; })}
);
};
handleSubmit
函数中,您有以下语句:

setUsers(() => {
  return {
    newUsersList,
  };
});
它必须是以下内容:

setUsers(newUsersList);

由于传递给
setUsers
的参数不应该是函数,它应该是数组。

handleSubmit
函数中,您有以下语句:

setUsers(() => {
  return {
    newUsersList,
  };
});
它必须是以下内容:

setUsers(newUsersList);

由于传递给
setUsers
的参数不应该是函数,它应该是数组。

handleSubmit中更改
setUser
实现,如下所示:-

const newUsersList = [...users];
newUsersList.push(data);
setUsers(newUsersList);
您之前所做的是将您的状态(即
newUsersList
包装在
{}
中,使其成为类似
{newUsersList:content of newUsersList}的对象
并通过从状态更新程序的回调返回相同的值将其设置为状态,现在在访问此新状态下的
.map
时,它将失败,因为它不再是数组

因此,只需使用spread操作符复制现有状态,即
用户
,然后对新列表执行推送操作并将其设置为状态

您还可以执行以下操作:-

setUsers((prevUsers)=>[...prevUsers,data]);
在这里,您可以通过回调函数获得以前的状态,只需返回一个包含
prevUsers
+
数据的新数组即可

这也是可行的(本质上与第一个相同):-


但是,当对前一个状态进行操作时,最好使用该回调函数,因为
prevUsers
永远不会是过时的状态,以防闭包开始导致该状态。

handleSubmit
内部更改
setUser
实现,如下所示:-

const newUsersList = [...users];
newUsersList.push(data);
setUsers(newUsersList);
您之前所做的是将您的状态(即
newUsersList
包装在
{}
中,使其成为类似
{newUsersList:content of newUsersList}的对象
并通过从状态更新程序的回调返回相同的值将其设置为状态,现在在访问此新状态下的
.map
时,它将失败,因为它不再是数组

因此,只需使用spread操作符复制现有状态,即
用户
,然后对新列表执行推送操作并将其设置为状态

您还可以执行以下操作:-

setUsers((prevUsers)=>[...prevUsers,data]);
在这里,您可以通过回调函数获得以前的状态,只需返回一个包含
prevUsers
+
数据的新数组即可

这也是可行的(本质上与第一个相同):-


但是,当对前一个状态进行操作时,最好使用该回调函数,因为
prevUsers
永远不会是一个过时的状态,以防闭包开始导致该状态。

不过,我确实遇到了一些问题。您显示的第一种方式停止了错误,但页面没有刷新,第二种回调方式导致了预期的重新加载,但它发布了两次数据。我最终尝试了``setUser(prevUsers=>[…prevUsers]),然后它只更新了一次,这是预期的行为iour。另一个有效的方法就是执行setUser([…users]);我认为在第一个示例中,您没有将
新用户列表
分配给
[…用户]
,而是像@keimeno那样将其分配给
用户
,但这不对,因为我们需要一份副本。要制作副本,我们使用
。现在,每次复制时,即使不添加
数据
,也会进行渲染。因此,我不确定为什么仅仅复制现有状态而不使用新的
数据
会在渲染输出中获得新的
数据
。您必须使用
push
添加
data
(到您复制的状态),或者只需执行
[…状态,数据]
位。不过,我确实遇到了一些问题。您显示的第一种方式停止了错误,但页面没有引用