簡體   English   中英

TypeScript React 組件在 useState 聲明和將道具傳遞給子組件時出錯

[英]TypeScript Error in React component on useState declaration and passing props to child component

我開始將 TypeScript 與 React 一起使用,目前正在構建一個示例應用程序進行練習,只是從公共 API 獲取數據並與 Material UI 一起實現 CRUD,但我在兩個組件中遇到錯誤,因此非常感謝您的幫助。

第一個錯誤是通過 props 將 function 傳遞給子組件,第二個錯誤是使用我為我的數據類型創建的自定義接口聲明 useState。

第一個組件是 PostTable.tsx

const PostsTable: React.FunctionComponent = () => {
  const [posts, setPosts] = useState<Array<IPost>>([]);
  const [selectedPost, setSelectedPost] = useState<IPost | null>(null);
  const [dialogOpen, setDialogOpen] = useState<boolean>(false);

  const fetchPosts = () => {
    PostService.getAllPosts()
      .then((response: any) => {
        setPosts(response.data);
      })
      .catch((e: Error) => {
        console.log(e);
      });
  };

  useEffect(() => {
    fetchPosts();
  }, [posts]);

  const editPost = (post: IPost) => (event: any) => {
    setSelectedPost(post);
    setDialogOpen(true);
  };

  const handleClose = () => {
    setDialogOpen(false);
  };

  const deletePost =
    (id: number): any =>
    (event: Event) => {
      event.stopPropagation();
      PostService.deletePost(id)
        .then((response: any) => {
          setPosts(response.data);
          console.log(posts);
        })
        .catch((e: Error) => {
          console.log(e);
        });
    };

  return (
    <Container fixed>
      {!posts || posts.length < 1 ? (
        <div style={{ display: 'flex', justifyContent: 'center' }}>
          <CircularProgress color="primary" size={100} />
        </div>
      ) : (
        <TableContainer component={Paper}>
          <Table sx={{ minWidth: 650 }} aria-label="simple table">
            <TableHead>
              <TableRow>
                <TableCell align="left">User Id</TableCell>
                <TableCell align="left">Post Id</TableCell>
                <TableCell align="left">Title</TableCell>
                <TableCell align="left">Actions</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {posts.map((post: IPost) => (
                <TableRow
                  key={post.id}
                  sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
                >
                  <TableCell>{post.userId}</TableCell>
                  <TableCell align="left">{post.id}</TableCell>
                  <TableCell align="left">{post.title}</TableCell>
                  <TableCell align="left">
                    <Tooltip title="Delete">
                      <IconButton onClick={editPost(post)}>
                        <EditIcon />
                      </IconButton>
                    </Tooltip>
                    <Tooltip title="Edit">
                      <IconButton onClick={deletePost(post.id)}>
                        <DeleteIcon />
                      </IconButton>
                    </Tooltip>
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </TableContainer>
      )}
      {
        <EditPostDialog
          open={dialogOpen}
          handleClose={handleClose}
          /**Error is on this line**/
          selectedPost={selectedPost}
        />
      }
    </Container>
  );
};

其次,子 EditPostDialog.ts

const EditPostDialog: React.FunctionComponent<IEditPostDialog> = (
  props: IEditPostDialog
) => {
  const { open, handleClose, selectedPost } = props;
  /**Error on this line**/
  const [post, setPost] = useState<IPost>({});

  useEffect(() => {
    const newPost = {
      id: selectedPost.id,
      userId: selectedPost.userId,
      title: selectedPost.title,
      body: selectedPost.body,
    };
    setPost(newPost);
  }, [selectedPost]);

  const handleChange = (event: any) => {
    setPost({ ...post, [event.target.name]: event.target.value });
  };

  const handleSubmit = () => {
    PostService.updatePost(post.id, post);
    handleClose();
  };

  return (
    <Dialog onClose={handleClose} open={open}>
      <DialogTitle id="simple-dialog-title">Post info</DialogTitle>
      <DialogContent classes={{ root: 'dialog-content' }}>
        <TextField
          id="id"
          label="Post Id"
          name="id"
          variant="outlined"
          value={post.id}
          onChange={handleChange}
        />
        <TextField
          id="userId"
          label="User Id"
          name="userId"
          variant="outlined"
          value={post.userId}
          onChange={handleChange}
        />
        <TextField
          id="title"
          label="Title"
          name="title"
          variant="outlined"
          value={post.title}
          onChange={handleChange}
        />
        <TextField
          id="body"
          label="Body"
          name="body"
          variant="outlined"
          value={post.body}
          onChange={handleChange}
        />
      </DialogContent>
      <DialogActions>
        <Button onClick={handleClose}>Close</Button>
        <Button onClick={handleSubmit}>Submit</Button>
      </DialogActions>
    </Dialog>
  );
};

您可能需要 IPost 接口,所以它是:

export default interface IPost {
  userId: number;
  id: number;
  title: string;
  body: string;
}

最后是 IEditPost 界面:

export default interface IEditPostDialog {
  open: boolean;
  handleClose: () => void;
  selectedPost: IPost;
}

提前謝謝大家!

第二個錯誤基本上是您使用空的 object 初始化 IPost 類型的IPost 但是界面希望您的所有屬性都存在。 您可以通過附加? 在物業名稱之后。

您可以簡化您的子組件來解決這個問題:

const [post, setPost] = useState<IPost>(selectedPost);

  useEffect(() => {
    setPost(selectedPost);
  }, [selectedPost]);

如果您遇到其他問題:首先,您不需要明確指定null

// Your code: const [selectedPost, setSelectedPost] = useState<IPost | null>(null);
const [selectedPost, setSelectedPost] = useState<IPost>(null); // should work perfectly fine

我們需要查看接口IEditPostDialog以了解將值selectedPost傳遞給底層組件的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM