I'm starting to learn React, more specifically ReactJS, and now I've got my NodeJS backend, where I'm storing an array of projects, which contains: id(uuid), url(string), techs(array of strings), title(string) and likes(number).
My component is rendering a div for each of the projects that my backend sends to the frontend, and each div will contain all the attributes of the project, and also a button that will trigger a route on my backend to increment the number of likes. It was supposed to update that number at the same time of the button click, and I'd like to do that without needing to request all the list of projects to the API again.
Well, my component is like this:
import React, { useContext, useEffect, useState } from 'react';
import { ThemeContext } from '../../providers/ThemeContext';
import { Button } from '@material-ui/core';
import axios from '../../services/axios';
function ListProjects() {
const [projects, setProjects] = useState<any[]>([]);
const { theme } = useContext(ThemeContext);
const updateProjects = async () => {
const res = await axios.get('list');
res.data.status === 1 && setProjects(res.data.projects);
};
useEffect(() => {
updateProjects();
}, []);
const onLikeProject = async (id: string) => {
const newObj = (await axios.post(`${id}/like`)).data.updatedProject;
const objIndex = projects.findIndex(i => i.id === id);
let projectsCopy = projects;
/* console.log(projects[objIndex]); */
projectsCopy[objIndex] = newObj;
/* console.log(projectsCopy[objIndex]); */
setProjects(projectsCopy);
/* console.log(projects[objIndex]); */
};
return (
<div style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
minHeight: 'calc(100vh - 64px)',
minWidth: '100vw',
backgroundColor: theme.bg,
color: theme.color
}}>
{ projects && projects.map((p, i) => <div key={p.id} style={{
display: 'flex',
flexDirection: 'column',
width: '550px',
height: '300px',
border: '1px solid blue',
marginBottom: '10px'
}}>
<h3>Title: { p.title }</h3>
<h3>URL: { p.url }</h3>
<h3>Techs: { p.techs.map((t: any, i: any) => i+1 < p.techs.length ? `${t}, ` : t) }</h3>
<h3>Likes: { p.likes }</h3>
<Button color="primary" variant="contained" onClick={() => onLikeProject(p.id) }>Like</Button>
</div>) }
</div>
);
}
export default ListProjects;
As you can see, when the page loads, the projects state is updated with the API list response. I have already tried using the same updateProjects()
function to update the list when the user click the Like button, but this triggers another api call, and that will delay a little, and making an api list request on every single like request, would break a possible limit of requests the service has available. So I tried the code inside the onLikeProject()
, but it doesn't update the UI, even if the projects array is being updated.
How should I proceed? Thanks