将 useState 与具有多个布尔字段的对象反应
React useState with Object with multiple boolean fields
我用 useState 初始化了这个对象:
const [
emailNotifications,
setEmailNotifications,
] = useState<emailNotifications>({
rating: false,
favourites: false,
payments: false,
refunds: false,
sales: false,
});
我创建了一个函数,该函数应该动态更改每个字段的值,但我正在努力为 onClick 分配相反的布尔值。这是函数:
const handleEmailNotificationsSettings = (
event: React.ChangeEvent<HTMLInputElement>
) => {
setEmailNotifications({
...emailNotifications,
[event.target.id]: !event.target.id,
});
};
我做错了什么?
你的方法是正确的,只是你试图在这里实现的一件小事是错误的。
setEmailNotifications({
...emailNotifications,
[event.target.id]: !event.target.id, //Here
});
当您将动态值设置为您期望的状态时,它是不是
的布尔值
解决方案:
setEmailNotifications({
...emailNotifications,
[event.target.id]: !emailNotifications[event.target.id],
});
@kunal panchal 的回答完全有效 Javascript,但它确实会导致 Typescript 错误,因为 event.target.id
的类型是 string
所以 Typescript 不确定它是emailNotifications
的有效密钥。您必须使用 as
.
来断言它是正确的
!emailNotifications[event.target.id as keyof EmailNotifications]
避免这种情况的一种方法是通过查看 input
上的 checked
属性 而不是切换状态来获取 boolean
值。
作为旁注,使用 setState
回调获取当前状态是一个很好的最佳实践,这样如果多个更新一起批处理,您始终可以获得正确的值。
const _handleEmailNotificationsSettings = (
event: React.ChangeEvent<HTMLInputElement>
) => {
setEmailNotifications(prevState => ({
...prevState,
[event.target.id]: event.target.checked,
}));
};
这可能是复选框的最佳解决方案。
另一种对其他情况更灵活的方法是使用柯里化函数。我们不是从 event.target.id
获取 属性,它总是 string
,而是将 property
作为参数传递,为每个 [=52= 创建一个单独的处理程序].
const handleEmailNotificationsSettings = (
property: keyof EmailNotifications
) => () => {
setEmailNotifications((prevState) => ({
...prevState,
[property]: !emailNotifications[property]
}));
};
或
const handleEmailNotificationsSettings = (
property: keyof EmailNotifications
) => (event: React.ChangeEvent<HTMLInputElement>) => {
setEmailNotifications((prevState) => ({
...prevState,
[property]: event.target.checked
}));
};
你这样使用:
<input
type="checkbox"
checked={emailNotifications.favourites}
onChange={handleEmailNotificationsSettings("favourites")}
/>
这些解决方案避免了必须在事件处理程序中做出 as
断言,但有时它们是不可避免的。我正在使用 (Object.keys(emailNotifications)
遍历你的状态,我需要在那里做一个断言,因为 Object.keys
总是 returns string[]
.
import React, { useState } from "react";
// I am defining this separately so that I can use typeof to extract the type
// you don't need to do this if you have the type defined elsewhere
const initialNotifications = {
rating: false,
favourites: false,
payments: false,
refunds: false,
sales: false
};
type EmailNotifications = typeof initialNotifications;
const MyComponent = () => {
// you don't really need to declare the type when you have an initial value
const [emailNotifications, setEmailNotifications] = useState(
initialNotifications
);
const handleEmailNotificationsSettings = (
property: keyof EmailNotifications
) => (event: React.ChangeEvent<HTMLInputElement>) => {
setEmailNotifications((prevState) => ({
...prevState,
[property]: event.target.checked
}));
};
return (
<div>
{(Object.keys(emailNotifications) as Array<keyof EmailNotifications>).map(
(property) => (
<div key={property}>
<label>
<input
type="checkbox"
id={property}
checked={emailNotifications[property]}
onChange={handleEmailNotificationsSettings(property)}
/>
{property}
</label>
</div>
)
)}
</div>
);
};
export default MyComponent;
我用 useState 初始化了这个对象:
const [
emailNotifications,
setEmailNotifications,
] = useState<emailNotifications>({
rating: false,
favourites: false,
payments: false,
refunds: false,
sales: false,
});
我创建了一个函数,该函数应该动态更改每个字段的值,但我正在努力为 onClick 分配相反的布尔值。这是函数:
const handleEmailNotificationsSettings = (
event: React.ChangeEvent<HTMLInputElement>
) => {
setEmailNotifications({
...emailNotifications,
[event.target.id]: !event.target.id,
});
};
我做错了什么?
你的方法是正确的,只是你试图在这里实现的一件小事是错误的。
setEmailNotifications({
...emailNotifications,
[event.target.id]: !event.target.id, //Here
});
当您将动态值设置为您期望的状态时,它是不是
的布尔值解决方案:
setEmailNotifications({
...emailNotifications,
[event.target.id]: !emailNotifications[event.target.id],
});
@kunal panchal 的回答完全有效 Javascript,但它确实会导致 Typescript 错误,因为 event.target.id
的类型是 string
所以 Typescript 不确定它是emailNotifications
的有效密钥。您必须使用 as
.
!emailNotifications[event.target.id as keyof EmailNotifications]
避免这种情况的一种方法是通过查看 input
上的 checked
属性 而不是切换状态来获取 boolean
值。
作为旁注,使用 setState
回调获取当前状态是一个很好的最佳实践,这样如果多个更新一起批处理,您始终可以获得正确的值。
const _handleEmailNotificationsSettings = (
event: React.ChangeEvent<HTMLInputElement>
) => {
setEmailNotifications(prevState => ({
...prevState,
[event.target.id]: event.target.checked,
}));
};
这可能是复选框的最佳解决方案。
另一种对其他情况更灵活的方法是使用柯里化函数。我们不是从 event.target.id
获取 属性,它总是 string
,而是将 property
作为参数传递,为每个 [=52= 创建一个单独的处理程序].
const handleEmailNotificationsSettings = (
property: keyof EmailNotifications
) => () => {
setEmailNotifications((prevState) => ({
...prevState,
[property]: !emailNotifications[property]
}));
};
或
const handleEmailNotificationsSettings = (
property: keyof EmailNotifications
) => (event: React.ChangeEvent<HTMLInputElement>) => {
setEmailNotifications((prevState) => ({
...prevState,
[property]: event.target.checked
}));
};
你这样使用:
<input
type="checkbox"
checked={emailNotifications.favourites}
onChange={handleEmailNotificationsSettings("favourites")}
/>
这些解决方案避免了必须在事件处理程序中做出 as
断言,但有时它们是不可避免的。我正在使用 (Object.keys(emailNotifications)
遍历你的状态,我需要在那里做一个断言,因为 Object.keys
总是 returns string[]
.
import React, { useState } from "react";
// I am defining this separately so that I can use typeof to extract the type
// you don't need to do this if you have the type defined elsewhere
const initialNotifications = {
rating: false,
favourites: false,
payments: false,
refunds: false,
sales: false
};
type EmailNotifications = typeof initialNotifications;
const MyComponent = () => {
// you don't really need to declare the type when you have an initial value
const [emailNotifications, setEmailNotifications] = useState(
initialNotifications
);
const handleEmailNotificationsSettings = (
property: keyof EmailNotifications
) => (event: React.ChangeEvent<HTMLInputElement>) => {
setEmailNotifications((prevState) => ({
...prevState,
[property]: event.target.checked
}));
};
return (
<div>
{(Object.keys(emailNotifications) as Array<keyof EmailNotifications>).map(
(property) => (
<div key={property}>
<label>
<input
type="checkbox"
id={property}
checked={emailNotifications[property]}
onChange={handleEmailNotificationsSettings(property)}
/>
{property}
</label>
</div>
)
)}
</div>
);
};
export default MyComponent;