DEV Community

Cover image for How to juggle in between two containers (ReactJS)
Surapat Mekvanich
Surapat Mekvanich

Posted on

How to juggle in between two containers (ReactJS)

Hi all,

In phase 2 of my coding bootcamp we were learning React (framework on top of JavaScript I had wanted to do something a little bit different. Also, at this point in time we didn't learn how to build the backend yet. I had to generate a mock data in JSON format and then host that in order for my front end to fetch data to display from.

This project was to showcase Bob Ross's paintings. My initial thoughts was that I will have two containers. One container showing all of Bob Ross's paintings (container A) and the other would be where you can favorite them (container B).

However, I want to copy (THEN delete) the information of the container A and send it to container B. And, vice versa.

First, what I had to do was to fetch the data for both container A and B. The initial data for container B was to be empty (because no favorites yet).

 useEffect(() => { // fetch paintings
  const fetchData = async () => {
    try {
      const resp = await fetch("http://localhost:3000/paintings")
      const paintings = await resp.json()
      setPaintings(paintings)
    } catch (error) {
      alert(error)
    }
   }
   fetchData()
}, [])
Enter fullscreen mode Exit fullscreen mode

I also did this with the other container (B). Then, I want to mapped all the data into each container's cards. So, then I created all the respective container A/B cards for them to have SOC.

const mappedPaintings = paintings.map(painting => (<PaintingCard key={painting.id} /> 
)
)
Enter fullscreen mode Exit fullscreen mode

paintings = refers to the inherited useState value from its parental component through props
PaintingCard (component) = the child component of the container A

Note: I also passed down a couple more props down into this child container as well but to not clog the code and make it look confusing I will omit them.

Thereafter, building a structure for my JSX.

return(
<div>
{mappedPaintings}
</div>
)
Enter fullscreen mode Exit fullscreen mode

Then, inside the PaintingCard component I passed down a couple useState set functions. I won't note it here but it'll be assumed.

So again, building a simple JSX structure.

return(
<div>

<div>
{painting.title}
</div>
<img src={painting.img_src} alt={painting.title} />
<button onClick={handleDelete}>Add to My Gallery</button>

</div>
)
Enter fullscreen mode Exit fullscreen mode

So now our mapped Data should show us the painting title and image. I also build a button to handle delete... that's kinda misleading since it'll fire a POST request before deleting itself. For simplicity sake I chose that name so please bear with it.

As for the handleDelete callback function,

const { id } = useParams()
const finalPainting = !painting ? myPainting : painting
const handleDelete = () => {
const paintingToAdd = {...finalPainting, id:null }

        fetch("http://localhost:3000/gallery",{
            method: "POST",
            headers:{
                "Content-Type": "application/json"
            },
            body: JSON.stringify(paintingToAdd)
        })
        .then(response => response.json())
        .then(paintingObj => setMyPaintings(currentVal => [paintingObj, ...currentVal]))
        .catch(error => alert(error))

        fetch(`http://localhost:3000/paintings/${painting.id}`,
            {
                method: "DELETE"
            })
        setPaintings(currentPaintings => currentPaintings.filter(element => element.id !== painting.id))
    }
Enter fullscreen mode Exit fullscreen mode

A lot to take in, I know. Even worse when you're trying to build this. Remember that I need to have another one going vice versa. I will walkthrough each part.

const finalPainting = !painting ? myPainting : painting
Enter fullscreen mode Exit fullscreen mode

This variable determines which painting we are choosing

const paintingToAdd = {...finalPainting, id:null }
Enter fullscreen mode Exit fullscreen mode

This spreads (iterates/copy all of its object) the finalPainting variable and sets the id of each object to null. ***

 fetch("http://localhost:3000/gallery",{
            method: "POST",
            headers:{
                "Content-Type": "application/json"
            },
            body: JSON.stringify(paintingToAdd)
        })
        .then(response => response.json())
        .then(paintingObj => setMyPaintings(currentVal => [paintingObj, ...currentVal]))
        .catch(error => alert(error))
Enter fullscreen mode Exit fullscreen mode

This fires a POST fetch to mock database (and stringify the object we are sending) and renders/set the state for the container B, and to alert us if it catches any error.

 fetch(`http://localhost:3000/paintings/${painting.id}`,
            {
                method: "DELETE"
            })
        setPaintings(currentPaintings => currentPaintings.filter(element => element.id !== painting.id))
Enter fullscreen mode Exit fullscreen mode

This fires a DELETE fetch to mock database. I made use of useParams to target the right painting by interpolating the id into the path. Then, it renders/set the state for the container A by getting any painting that DOESN'T have the painting id that we JUST deleted.

***I had to set id to null because if you don't and you send back the painting with the same id the database will not like that because id is the unique identifier... meaning there can be only one of that value. So, setting all the id to null addresses this problem.

We have successfully move content from container A to B while erasing the original content from container A.

Now, I just did the same but going from container B to A.
There you have it, a 'juggling container system' (I coined it).

Thanks for reading!

Top comments (0)