将AsyncThunkAction传递给unwrapResult

问题描述

我正在关注Redux Essentials教程,并且在第5部分Async Logic and Data Fetching中遇到了问题。尽管本教程中未使用TypeScript,但我仍在使用TypeScript,因为我想同时学习Redux和TypeScript。

Checking Thunk Results in Components部分中,调用Redux的unwrapResult函数时遇到无法识别的类型错误。

这是错误:

TypeScript error in redux-essentials-example-app/src/features/posts/AddPostForm.tsx(34,22):
Argument of type 'AsyncThunkAction<Post,InitialPost,{}>' is not assignable to parameter of type 'ActionTypesWithOptionalErrorAction'.
  Property 'payload' is missing in type 'AsyncThunkAction<Post,{}>' but required in type '{ error?: undefined; payload: any; }'.  TS2345

    32 |         setAddRequestStatus("pending");
    33 |         const result = await dispatch(addNewPost({ title,content,user: userId }));
  > 34 |         unwrapResult(result);
       |                      ^
    35 |         setTitle("");
    36 |         setContent("");
    37 |         setUserId("");

这是我键入的AddPostForm.tsx版本的完整内容:

import React,{ useState } from "react";
import { useDispatch,useSelector } from "react-redux";
import { unwrapResult } from "@reduxjs/toolkit";

import { RootState } from "../../app/store";
import { addNewPost } from "./postsSlice";

export default function AddPostForm() {
  const [title,setTitle] = useState("");
  const [content,setContent] = useState("");
  const [userId,setUserId] = useState("");
  const [addRequestStatus,setAddRequestStatus] = useState("idle");

  const dispatch = useDispatch();
  const users = useSelector((state: RootState) => state.users);

  const onTitleChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
    setTitle(e.target.value);
  };
  const onContentChanged = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    setContent(e.target.value);
  };
  const onAuthorChanged = (e: React.ChangeEvent<HTMLSelectElement>) => {
    setUserId(e.target.value);
  };

  const canSave = [title,userId].every(Boolean) && addRequestStatus === "idle";

  const onSavePostClicked = async () => {
    if (canSave) {
      try {
        setAddRequestStatus("pending");
        const result = await dispatch(addNewPost({ title,user: userId }));
        unwrapResult(result);
        setTitle("");
        setContent("");
        setUserId("");
      } catch (err) {
        console.error("Failed to save the post: ",err);
      } finally {
        setAddRequestStatus("idle");
      }
    }
  };

  const usersOptions = users.map(user => (
    <option key={user.id} value={user.id}>
      {user.name}
    </option>
  ));

  return (
    <section>
      <h2>Add a new post</h2>
      <form>
        <label htmlFor="postTitle">Post Title:</label>
        <input type="text" id="postTitle" name="postTitle" value={title} onChange={onTitleChanged} />
        <label htmlFor="postAuthor">Author:</label>
        <select id="postAuthor" value={userId} onChange={onAuthorChanged}>
          <option value=""></option>
          {usersOptions}
        </select>
        <label htmlFor="postContent">Content:</label>
        <textarea id="postContent" name="postContent" value={content} onChange={onContentChanged} />
        <button type="button" onClick={onSavePostClicked} disabled={!canSave}>Save post</button>
      </form>
    </section>
  );
}

这是我键入的redux-essentials-example-app / src / features / posts / postsSlice.tsx的完整内容:

import { createAsyncThunk,createSlice } from "@reduxjs/toolkit";

import { RootState } from "../../app/store";
import { client } from "../../api/client";

export interface PostState {
  posts: Post[],status: "idle" | "loading" | "succeeded" | "failed",error: string | null,}

export interface Post {
  id: string,date: string,title: string,content: string,user: string,reactions: Reactions,}

export interface Reactions {
  thumbsUp: number,hooray: number,heart: number,rocket: number,eyes: number,[key: string]: number,}

const initialState: PostState = {
  posts: [],status: "idle",error: null,};

export const fetchPosts = createAsyncThunk("posts/fetchPosts",async () => {
  const response = await client.get("/fakeApi/posts");
  return response.posts;
});

interface InitialPost {
  title: string,}

export const addNewPost = createAsyncThunk<Post,InitialPost>(
  "posts/addNewPost",async (initialPost) => {
    const response = await client.post("/fakeApi/posts",{ post: initialPost });
    return response.post;
  }
);

const postsSlice = createSlice({
  name: "posts",initialState,reducers: {
    postUpdated: (state,action) => {
      const { id,title,content } = action.payload;
      const existingPost = state.posts.find(post => post.id === id);

      if (existingPost) {
        existingPost.title = title;
        existingPost.content = content;
      }
    },reactionAdded: (state,action) => {
      const { postId,reaction } = action.payload;
      const existingPost = state.posts.find((post: Post) => post.id === postId);
      if (existingPost) {
        existingPost.reactions[reaction]++;
      }
    },},extraReducers: builder => {
    builder.addCase(fetchPosts.pending,(state) => {
      state.status = "loading";
    });
    builder.addCase(fetchPosts.fulfilled,(state,action) => {
      state.status = "succeeded";
      state.posts = state.posts.concat(action.payload);
    });
    builder.addCase(fetchPosts.rejected,action) => {
      state.status = "failed";
      if (action.error.message) {
        state.error = action.error.message;
      }
    });
    builder.addCase(addNewPost.fulfilled,action) => {
      state.posts.push(action.payload);
    });
  },});

export const { postUpdated,reactionAdded } = postsSlice.actions;

export function selectAllPosts(state: RootState) {
  return state.posts.posts;
}

export function selectPostById(state: RootState,postId: string) {
  return state.posts.posts.find((post: Post) => post.id === postId);
}

export default postsSlice.reducer;

我查看了Redux Toolkit的源代码,并且未导出ActionTypesWithOptionalErrorAction类型,因此似乎传递给unwrapResult的对象必须是某种形状,而不是声明为某种形状。类型。类型错误表示缺少payload属性,但是如果我注释掉unwrapResult调用并改为使用console.log(result)检查对象,则肯定存在该属性。因此,这似乎是使类型正确的问题,而不是代码中的逻辑错误。如何正确输入?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)