I am creating my first project in React which essentially is a big list of pictures that are being sorted a specific way (and you can like/dislike them). Data is gathered from an API. I was able to do sorting between routes based on amounts of likes and dislikes and wanted to add a favourite button, which will put the favourited item to the top of the list, but I actually got stuck trying to figure it out. I thought about creating starred
state and change it when user click the star button but sorting mechanism is done in another component.
I know there must be some rookie mistake and issue is with how I decided to use components and their states.
The compontent looks like this:
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import axios from "axios";
import * as constants from "../constants/constants";
export function ImageCompontent({ element, setImageChangedFlag }) {
const [title, setTitle] = useState(element.title);
const [img, setImg] = useState(element.img);
const [upvotes, setUpvotes] = useState(element.upvotes);
const [downvotes, setDownvotes] = useState(element.downvotes);
const [starred, setStarred] = useState(false);
const location = useLocation().pathname;
const updateStateAndReturnPayload = (type, response) => {
switch (type) {
case "upvotes":
setUpvotes(response.data.upvotes + 1);
return {
...response.data,
upvotes: response.data.upvotes + 1,
};
case "downvotes":
setDownvotes(response.data.downvotes + 1);
return {
...response.data,
downvotes: response.data.downvotes + 1,
};
default:
return {
...response.data,
};
}
};
const updateLikes = (type) => () => {
axios
.get(constants.endpoints.SEVERALIMAGES(element.id))
.then((response) => {
const payload = updateStateAndReturnPayload(type, response);
return axios.put(constants.endpoints.SPECIFICIMAGE(element.id), payload);
})
.then((response) => {
console.log("Success:", response.data);
})
.catch((error) => {
console.error("Error:", error);
});
};
const changeStarredAndImageListState = () => {
if (starred) {
setStarred(false);
} else {
setStarred(true);
}
setImageChangedFlag(true);
};
useEffect(() => {
if (
(location === constants.routes.MOSTLIKESPAGEROUTE &&
upvotes - downvotes <= 100) ||
(location === constants.routes.NORMALPAGEROUTE &&
upvotes - downvotes > 100)
) {
console.log("change needed");
setMemeChangedFlag(true);
}
}, [upvotes, downvotes, setMemeChangedFlag, location]);
return (
<div>
<h1>{title}</h1>
<img src={img} alt={`Image containing ${title}`} />
<h2>{upvotes}</h2>
<h2>{downvotes}</h2>
<button onClick={updateLikes("upvotes")}>Upvote</button>
<button onClick={updateLikes("downvotes")}>Downvote</button>
<h2 onClick={changeStarredAndImageListState}>
{starred ? "*" : "I like it!"}
</h2>
</div>
);
}
and the component that is a list rendering smaller components:
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import axios from "axios";
import { ImageCompontent } from "./ImageComponent";
import * as constants from "../constants/constants";
const ImageListComponent = () => {
const [images, setImages] = useState(null);
const [imageChangedFlag, setImageChangedFlag] = useState(false);
const location = useLocation().pathname;
useEffect(() => {
axios.get(constants.endpoints.SEVERALIMAGES).then((response) => {
const imgList = response.data;
const filteredList = imgList.filter((element) => {
if (
location === constants.routes.MOSTLIKESPAGEROUTE ||
location === constants.routes.NORMALROUTE
) {
return element ? element.upvotes - element.downvotes > 100 : null;
} else {
return element ? element.upvotes - element.downvotes <= 100 : null;
}
});
setImages(filteredList);
setImageChangedFlag(false);
});
}, [imageChangedFlag, location]);
return (
<div>
{images ? (
images.map((element) => {
return (
<ImageCompontent
key={element.id}
element={element}
setImageChangedFlag={setImageChangedFlag}
></ImageCompontent>
);
})
) : (
<p>Loading...</p>
)}
</div>
);
};
export default ImageListComponent;
any help, a hint or even tips to get this code better and how to get favourites done much appreciated!