【问题标题】:×React - TypeError: Cannot read properties of undefined (reading 'userName')×React - TypeError:无法读取未定义的属性(读取“用户名”)
【发布时间】:2021-10-31 19:54:32
【问题描述】:

谁能解释一下这个 我正在通过我的服务器获取 json 那个 json 包含我在博客中使用的信息 所以我可以访问 blog.blogTitle 但我无法访问 blog.owner.userName 这对我来说毫无意义,因为我在状态上一次设置整个 json 然后使用它 谁能告诉我原因?以及如何避免它

function Blog(props) {
    const isUserAuthenticated = useSelector(state => state.getUser.authenticated)

    const user = useSelector(state => state.getUser.user)

    const [blog, setBlog] = useState([])

    const [dataMounted, setDataMounted] = useState(false)

    const [blogComments, setBlogComments] = useState([])

    const handleCommentSubmission = (e) => {
        const body = {
            blogId: blog.id,
            comment: e.comment,
            userName: user.userName
        }
        console.log(body)

        axios.post('http://localhost:8989/blog/comment', body, APIService.config).then(response => {
            console.log(response.data)
        }).catch(err => {
            console.log("Error while fetching comment: " + err)
            console.log("Error while fetching comment Server response: " + err.response)
        })

        return false;
    }

    const commentSchema = yup.object().shape({
            comment: yup
                .string().required('Comment is required')
                .min(2, 'Minimum 2 characters required')
                .max(300, "Maximum 300 characters allowed"),
        }
    );

    useEffect(() => {

        APIService.getBlogById(props.match.params.id).then(response => {
            setBlog(response.data)
            setBlogComments([])

            console.log('comments:', response.data)
            if (!response.data.comments.includes(null)) {
                response.data.comments.forEach(commentId => {
                    APIService.getCommentById(commentId).then(comment => {
                        blogComments.push(comment.data)
                    })
                })
            }

            console.log("Blog comments  ", blogComments)
        }, [])
        setDataMounted(true)

    }, [])

    return (
        <>
            <div className='blog-container'>

                <Card className="bg-dark text-white blog-banner">
                    <Card.Img
                        className='blog-banner'
                        src="https://image.freepik.com/free-vector/abstract-dotted-banner-background_1035-18160.jpg"
                        alt="Card image"/>
                    <Card.ImgOverlay>
                        <Card.Title className='blog-title'>{blog.blogTitle}</Card.Title>
                    </Card.ImgOverlay>

                </Card>


                <Breadcrumb>
                    <Breadcrumb.Item href="#">Home</Breadcrumb.Item>
                    <Breadcrumb.Item href={"/blog/" + blog.blogCategory}>
                        {blog.blogCategory}
                    </Breadcrumb.Item>
                    <Breadcrumb.Item active>{blog.blogTitle}</Breadcrumb.Item>
                </Breadcrumb>

                {dataMounted ?
                    <div className='blog-data-container'>
                        <p className='blog-data'>{blog.data}</p>
                        <p className='blog-owner'>Created By {blog.owner.userName}</p>
                    </div> : <></>
                }

                {isUserAuthenticated ?
                    <div>
                        <EditButton blog={blog}/>
                        <Button className='btn btn-primary'>
                            Delete Blog
                        </Button>
                    </div> : <></>
                }

                {
                    <div className='comment-form'>

                        {dataMounted && isUserAuthenticated ?
                            <Formik
                                initialValues={{
                                    blogTitle: '',
                                    data: '',
                                    blogCategory: '',
                                    accessStatus: ''
                                }}
                                onSubmit={(e) => handleCommentSubmission(e)}
                                validationSchema={commentSchema}
                            >{({
                                   handleSubmit,
                                   handleChange,
                                   handleBlur,
                                   values,
                                   touched,
                                   isValid,
                                   errors,
                               }) => (

                                <Form>
                                    <Form.Group placeholder='Type your blog here'
                                                controlId="blogForm.CommentTextArea">
                                        <Form.Control
                                            as='textarea'
                                            type="textarea"
                                            placeholder="Type your comment here"
                                            name="comment"
                                            value={values.comment}
                                            onChange={handleChange}
                                            isInvalid={!!errors.comment}
                                        />
                                        <Form.Control.Feedback type="invalid">
                                            {errors.comment}
                                        </Form.Control.Feedback>
                                    </Form.Group>

                                    <Button type='submit'
                                            onClick={(e) => handleSubmit(e)}> Add Comment </Button>
                                </Form>
                            )}
                            </Formik>

                            : <></>
                        }
                    </div>}


                <div className='comment-section-container'>
                    <p>{blogComments}</p>
                    {
                        blogComments.map((comment, index) => {
                            return (
                                <Container>
                                    <Row xs={2} md={4} lg={6}>
                                        <Col>1 of 2</Col>
                                        <Col>2 of 2</Col>
                                    </Row>
                                    <Row xs={1} md={2}>
                                        <Col>1 of 3</Col>
                                        <Col>2 of 3</Col>
                                        <Col>3 of 3</Col>
                                    </Row>
                                    <Row xs="auto">
                                        <Col>1 of 3</Col>
                                        <Col>2 of 3</Col>
                                        <Col>3 of 3</Col>
                                    </Row>
                                </Container>
                            )
                        })
                    }
                </div>
            </div>
        </>
    )
}

示例 Json

{id: '617ec3047c63c4643862ae51', blogTitle: 'some blog', data: 'datata', date: 1635698971568, owner: {…}, …}
blogAccessStatus: "PUBLIC"
blogCategory: "TECHNICAL"
blogTitle: "some blog"
comments: Array(1)
0: "617ec91bfdce2653b01b1d66"
length: 1
[[Prototype]]: Array(0)
data: "datata"
date: 1635698971568
id: "617ec3047c63c4643862ae51"
owner:
blogCount: 0
email: "bhavishya20@gmail.com"
userName: "bhavishya"
[[Prototype]]: Object
sharedWith: []
views: 0
[[Prototype]]: Object

【问题讨论】:

  • 你能发布你的 Json 吗?
  • 我已经分享了 json 和另外一件事,当我在页面预加载时进行编辑时它工作正常,但是当我刷新时它显示错误
  • 与主要问题不太相关,但您不应该blogComments.push(...)。相反,收集所有评论承诺,用Promise.all 等待它们,然后用所有承诺结果一起做setBlogComments(...)
  • 感谢您的帮助,这个承诺提示很有帮助,我现在无法渲染 cmets,非常感谢

标签: javascript reactjs


【解决方案1】:

setDataMounted(true) 指令应在setBlog(...) 之后调用。

【讨论】:

    【解决方案2】:

    您的博客呈现条件取决于dataMounted 状态。

    {dataMounted ?
      <div className='blog-data-container'>
      <p className='blog-data'>{blog.data}</p>
      <p className='blog-owner'>Created By {blog.owner.userName}</p>
    </div> : <></>
    }
    

    问题是您在回调之外将dataMounted 设置为true。这意味着它会在回调之前执行,以便为您的 blog 数据运行设置状态。解决您的问题的可能方法是

    APIService.getBlogById(props.match.params.id).then(response => {
       setBlog(response.data)
       setBlogComments([])
    
       console.log('comments:', response.data)
       if (!response.data.comments.includes(null)) {
           response.data.comments.forEach(commentId => {
               APIService.getCommentById(commentId).then(comment => {
                  blogComments.push(comment.data)
               })
           })
       }
    
       console.log("Blog comments  ", blogComments)
       setDataMounted(true) // setDataMounted should be called inside the callback
    }, [])
    

    【讨论】:

      猜你喜欢
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-27
      • 2016-05-08
      • 2021-12-09
      • 2021-12-31
      • 2021-11-13
      • 2022-01-14
      相关资源
      最近更新 更多