can anyone please explain me thiss i am getting a json through my server and that json contain the information i am using in the blog so i am able to access blog.blogTitle but i am not able to access blog.owner.userName it makes no sense to me because i am setting whole json at once on the state then using it can please anyone tell me the reason? and how to avoid it
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>
</>
)
}
Example 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: "[email protected]"
userName: "bhavishya"
[[Prototype]]: Object
sharedWith: []
views: 0
[[Prototype]]: Object
CodePudding user response:
The setDataMounted(true)
instruction should be invoked after setBlog(...)
.
CodePudding user response:
Your blog rendering condition depends on dataMounted
state.
{dataMounted ?
<div className='blog-data-container'>
<p className='blog-data'>{blog.data}</p>
<p className='blog-owner'>Created By {blog.owner.userName}</p>
</div> : <></>
}
The problem is you set dataMounted
to true
outside the callback. That means that it gets executed before the callback to set the state for your blog
data runs. A probable fix for your problem is
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
}, [])