不能通过useState更新对象



我是React的新手,学习状态和道具。我正在学习React Wes Bos课程,老师正在使用类组件,所以我在学习功能组件时进行了重构(为了练习,因为我必须学习这些)。

我们正在编写一个应该是一家鱼餐厅的应用程序,并且在某些时候,我们想要加载一些值到order部分。

我有两个主要问题:

1 -当我尝试在React开发工具中手动运行addToOrder(key)方法时通过在App.js上使用$r,我得到一个错误VM761:1 Uncaught TypeError: $r.addToOrder is not a function

2 -第二个问题是,当我点击按钮添加到订单,一个应该更新订单{}对象,订单对象本身没有得到更新.

我一直在寻找一个好的半天现在,我不知道什么可能是错误的。

作为自检:

  • prop索引被正确地从传递到,因为我可以console.log(index)并获得当前的。

我很抱歉,如果我没有适当地解释自己,这是有点难以浓缩成一个简短的帖子。如有需要,请提问题并澄清,我会尽力提供正确的信息。

下面是两个组件代码:

应用

import React from "react";
import { Header } from "./Header";
import { Order } from "./Order";
import { Inventory } from "./Inventory";
import { useState } from "react";
import sampleFishes from "../sample-fishes";
import { Fish } from "./Fish";
export const App = () => {
const [state, setState] = useState({
fishes: {},
order: {},
});
/**
* Structure of the function served in <AddFishForm>
* Making a copy of the state to avoid mutations ...state.fishes
* Date.now() used to assign a unique key
*
*/
const addFish = (fish) => {
const fishes = { ...state.fishes };
fishes[`fish${Date.now()}`] = fish;
setState({
fishes: fishes,
});
};
/**
* Function to display a sample fishes in the list
* Made to avoid manual typing
* Fish data comes from ../sample-fishes
*/
const loadSampleFishes = () => {
setState({ fishes: sampleFishes });
};
/**
* Take a copy of state
* Either add to the order or update the number in order
* (if order exists, adds one to it, if not, set it to one)
* Call setState() to update state object
*/
const addToOrder = (key) => {
const order = { ...state.order };
order[key] = order[key] + 1 || 1;
setState({
order: order,
});
};
return (
<div className="catch-of-the-day">
<div className="menu">
<Header tagline="Fresh Seafood Market" />
<ul className="fishes">
{Object.keys(state.fishes).map((key) => {
return (
<Fish
key={key}
details={state.fishes[key]}
addToOrder={addToOrder}
></Fish>
);
})}
</ul>
</div>
<Order />
<Inventory addFish={addFish} loadSampleFishes={loadSampleFishes} />
</div>
);
};

import React from "react";
import { formatPrice } from "../helpers";
export const Fish = ({ details, addToOrder, index }) => {
const isAvailable = details.status === "available";
const handleClick = () => {
addToOrder[index];
};
return (
<li className="menu-fish">
<img src={details.image} alt="" />
<h3 className="fish-names">
{details.name}
<span className="price">{formatPrice(details.price)}</span>
</h3>
<p>{details.desc}</p>
<button type="submit" disabled={!isAvailable} onClick={() => handleClick}>
{isAvailable ? "Add to order" : "Sold out!"}
</button>
</li>
);
};

从$r

调用函数TL;博士解决方案

现在我知道我在找什么,这是问题:更新和合并使用React useState钩子的对象。

我在更新订单{}时缺少复制之前的状态其余部分基本正确,因此改进的代码位是:

const addOrder = (key) => {
const order = { ...state.order };
order[key] = order[key] + 1 || 1;
setState({
...state,
order: order,
});
};

这篇文章(以及这个问题的最后一个答案)真的解释得很好:https://stackoverflow.com/a/61243124/20615843

这是React文档中的相对位:https://reactjs.org/docs/hooks-reference.html#functional-updates

显然,更好的做法是使用useReducer(),如下所述:https://stackoverflow.com/a/71093607/20615843

onClick={() => handleClick}应为

或者在末尾加上圆括号将其命名为

onClick={() => handleClick()} 

或者更好,直接作为回调方法传递

onClick={handleClick}

首先欢迎Jim Halpert来到react世界!祝你旅途愉快。

我在你的例子中发现了一些问题。

1)In the Fish。在调用实际函数时需要传递索引的JSX单击处理程序。

2)您必须将索引作为props从父JSX文件绑定。

3)由于在同一对象中有order和fishes,因此必须复制前面的数据以及App.jsx

第57行所示的数据我稍微调整了一下你的例子,看看下面:

import React from "react";
import { useState } from "react";
import { Fish } from "./Fish";
const App = () => {
const [state, setState] = useState({
fishes: {
"salmon" : {
"image":"https://via.placeholder.com/20x20",
"name":"salmon",
"description":"test",
"status":"available"
}
},
order: {},
});
/**
* Structure of the function served in <AddFishForm>
* Making a copy of the state to avoid mutations ...state.fishes
* Date.now() used to assign a unique key
*
*/
const addFish = (fish) => {
const fishes = { ...state.fishes };
fishes[`fish${Date.now()}`] = fish;
setState({
fishes: fishes,
});
};
/**
* Function to display a sample fishes in the list
* Made to avoid manual typing
* Fish data comes from ../sample-fishes
*/
const loadSampleFishes = () => {
setState({ fishes: sampleFishes });
};
/**
* Take a copy of state
* Either add to the order or update the number in order
* (if order exists, adds one to it, if not, set it to one)
* Call setState() to update state object
*/
const addToOrder = (fish) => {

const order = { ...state.order };
order[fish] = order[fish.key] + 1 ?? 1;
console.log("Order >>>>>>>>>>>> "+JSON.stringify(order));
setState({
...state,
order: order,
});
};
return (
<div className="catch-of-the-day">
<div className="menu">

<ul className="fishes">
{Object.keys(state.fishes).map((key) => {
return (
<Fish
index={key}
details={state.fishes[key]}
addToOrder={addToOrder}
></Fish>
);
})}
</ul>
</div>

</div>
);
};
export default App;

import React from "react";
export const Fish = ({ details, addToOrder, index }) => {
const isAvailable = details.status === "available";
const handleClick = (index) => {
addToOrder(index);
};
return (
<li className="menu-fish">
<img src={details.image} alt="" />
<h3 className="fish-names">
{details.name}
<span className="price">{details.price}</span>
</h3>
<p>{details.desc}</p>
<button type="submit" disabled={!isAvailable} onClick={() => handleClick(index)}>
{isAvailable ? "Add to order" : "Sold out!"}
</button>

</li>
);
};

最新更新