繁体   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