Reputation: 25
sorry i'm new to React. I'm trying to make a basic social network to learn react. Context: When i click on the "like" button, the setState should call the function to update the state of my component, but it is updated only when i refresh the page. I think the ComponentDidUpdate function isn't called like it should. What did i do wrong? Thanks for your help!
Here are the parts of the code :
Like button component:
class Like_Button extends React.Component {
constructor(props) {
super(props);
this.state = {liked : "Like"};
}
isliked(){
fetch("likes_of_user/")
.then(res => res.json())
.then((result) => {
result.map(x => {if(this.props.pk == x.liked_post){this.setState({liked: "Unlike"});}});
})
}
componentDidMount() {
this.isliked();
}
componentDidUpdate(prevProps, prevState) {
if (prevState.liked !== this.state.liked) {
this.isliked();
}
}
render() {
return (
<button className = "buttons" onClick={() => {
var csrftoken = getCookie('csrftoken');
fetch(`like_post/${this.props.pk}`, {method: "POST", headers: {'Accept': 'application/json', 'Content-Type': 'application/json','X-CSRFToken': csrftoken}})
}}>{this.state.liked}</button>
)
}
}
Newsfeed component:
class Newsfeed_comp extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
items: []
};
}
componentDidMount() {
fetch("get_newsfeed/")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
{items.map((item ,index) => (
<li className="postbox" key={`${item}${index}`}>
{item.author}
{item.date}
{item.content}
<Like_Button pk={item.id} />
</li>
))}
</ul>
);
}
}
}
ReactDom render:
ReactDOM.render(<Newsfeed_comp />, document.getElementById("newsfeed_view"))
Upvotes: 2
Views: 73
Reputation: 202618
Looks like you've reversed your logic, i.e. your button directly updates the data in the backend but does nothing to update component state, so the componentDidUpdate
isn't called as you've seen. The refresh is required so the component is remounted and the componentDidMount
can fetch the likes data.
Try instead to update local state first, then use componentDidUpdate
to issue the side-effect of updating the backend.
constructor(props) {
super(props);
this.state = { liked: true };
}
isliked() {
fetch("likes_of_user/")
.then(res => res.json())
.then((result) => {
result.map(x => {
if (this.props.pk === x.liked_post) {
this.setState({ liked: false });
}
});
})
}
componentDidUpdate(prevProps, prevState) {
if (prevState.liked !== this.state.liked) {
const csrftoken = getCookie('csrftoken');
fetch(
`like_post/${this.props.pk}`,
{
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken,
},
}
);
}
}
<button
className="buttons"
onClick={() => this.setState(
prevState => ({ liked: !prevState.liked })
)}
>
{this.state.liked ? "Liked" : "Unliked"}
</button>
Upvotes: 1
Reputation: 870
Try something like this:
LikeButton.js
import React, { useEffect, useState } from 'react';
export default function LikeButton({ pk }) {
const [like, setLike] = useState(false);
useEffect(() => {
const fetchLike = async () => {
const res = await fetch("likes_of_user/");
const result = await res.json();
if (result.length > 0) {
setLike(result.find(item => item.liked_post === pk));
}
};
try {
fetchLike();
} catch (error) {
// handle error
}
});
const handleClick = async () => {
const csrftoken = getCookie('csrftoken');
return fetch(`like_post/${pk}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken
},
method: 'POST',
});
};
return (
<button className='buttons' onClick={handleClick}>
{like}
</button>
);
};
NewsFeed.js
import React, { useEffect, useState } from 'react';
export function NewsFeed() {
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [items, setItems] = useState([]);
useEffect(() => {
const getNewsFeed = async () => {
const res = await fetch('get_newsfeed/');
const result = await res.json();
setIsLoaded(true);
setItems(result);
};
try {
getNewsFeed();
} catch (error) {
setIsLoaded(true);
setError(error);
}
});
if (error) return <div>Error: {error.message}</div>;
if (isLoaded) return <div>Loading...</div>;
const list = items.map((item) => (
<li className='postbox' key={item.content}>
{item.author}
{item.date}
{item.content}
<LikeButton pk={item.id} />
</li>
));
return <ul>{list}</ul>;
};
App.js
ReactDOM.render(<NewsFeed />, document.getElementById('newsfeed_view'));
Upvotes: 2