我最近在NextJS中切换到TypeScript(通过Create T3 App)。作为我的应用程序的一个组件,我想更新状态一旦Prisma突变。
我将setItems(通过useState初始化)传递给子组件,但是
仍然失败。Type error: Argument of type '(prev: Example[]) => (Example | undefined)[]' is not assignable to parameter of type 'SetStateAction<Example[]>'.
我的代码如下:
interface FormProps {
setItems: Dispatch<SetStateAction<Example[]>>;
}
const Form: FC<FormProps> = ({ setItems }) => {
const [message, setMessage] = useState("");
//setItems([])
const { mutate: createExample } = api.example.createExample.useMutation({
onSuccess: (data) => {
setItems((prev) => [...prev, data]);
},
});
return (
<form
className="flex gap-2"
onSubmit={(event) => {
event.preventDefault();
createExample({
text: message,
});
setMessage("");
}}
>
<input
type="text"
placeholder="Your message..."
minLength={2}
maxLength={100}
value={message}
onChange={(event) => setMessage(event.target.value)}
/>
<button
type="submit"
className="rounded-md border-2 border-zinc-800 p-2 focus:outline-none"
>
Submit
</button>
</form>
);
};
在我的主页中初始化setItems:
const Demo: NextPage = () => {
const [items, setItems] = useState<Example[]>([]);
const { data: session, status } = useSession();
const user = api.example.getAll.useQuery(["getAll"], {
onSuccess: (user) => {
setItems(user.examples);
},
});
const { mutate: deleteExample } = api.example.deleteExample.useMutation({
onSuccess(example) {
setItems((prev) => prev.filter((item) => item.id !== example.id));
},
});
return (
<>
{session ? (
<>
<p>Hello {session ? session.user?.name : null}</p>
<button
type="button"
onClick={() => {
signOut().catch(console.log);
}}
>
Logout
</button>
<br />
<ul>
{user.data
? items.map((example) => (
<li>
{example.text}{" "}
<button
onClick={() => {
deleteExample({ id: example.id });
}}
>
X
</button>
</li>
))
: null}
</ul>
<br />
<Form setItems={setItems} />
</>
) : (
<button
type="button"
onClick={() => {
signIn("email").catch(console.log);
}}
>
Login with Email
</button>
)}
</>
);
};
它似乎得到了正确的类型,知道它是一个' Example '。但是,抛出类型错误,因为我试图访问前一个状态。
如何在保持类型一致的情况下组合状态?
我认为问题是onSuccess
方法中的data
变量可能是undefined
。
并且typescript不希望将一个可能未定义的数组赋值给另一个未定义的数组
现在,我们如何解决这个问题?这得看情况。
为什么data
是undefined
?有三种可能:
data
总是未定义的(所以如果你把鼠标悬停在数据上,你应该看到data: undefined
)。
如果是这种情况,你要么有一些其他的bug导致data
是未定义的,或者你期望有一个未定义的列表,如果你这样做,通过将useState<Example[]>
更改为useState<(Example|undefined)[]>
和Dispatch<SetStateAction<Example[]>>
更改为Dispatch<SetStateAction<(Example|undefined)[]>>
来告诉typescript是这种情况。
data
有时未定义(data: Example|undefined
)。
如果Data有时未定义,则还有两种可能。或者您想要将undefined添加到列表中,或者您想要避免将undefined添加到列表中。
如果你想在列表中添加undefined,请按照上一步操作。
如果您不想将undefined添加到列表中,只需在运行setItems
函数之前确保它不是undefined:
onSuccess: (data) => {
if (data)
setItems((prev) => [...prev, data]);
},
如果在此之后你仍然收到错误,做以下更改:[...prev, data as Example]
- 数据从不是未定义的。
如果你知道data
永远不会被定义,但它仍然被定义,并且没有办法改变这个事实,你可以使用前一种情况的代码告诉typescript:
setItems((prev) => [...prev, data as Example]);
上述情况之一应能解决问题。