skip to Main Content

I want to build a webapp that displays the image in a div of the Parent component when clicking on an item in the list generated by the child component. I figured it was best to generate the list in a child component, as it will be dynamic. Now, I have it working that the list is being generated and sent back to the parent component as a div, but how do I include a variable (e.g. the ID) that points to the image that is clicked?

Is it maybe necessary send the whole image list to the child component, and generate the list there? Maybe even the whole main to keep it in one component? I’m pretty new to React/ NextJS so I could really use some guidance. Here is the code to give you an idea of what’s going on:

Simplified parent component:

import Paintings from "./components/Paintings";

export default function Gallery() {

    var images = require('/public/gallerij.json');
    // Json file with this structure:
    [
  {
    "Number": 1,
    "Title": "Moments of Magic",
    "Size": "70x50cm",
    "Paint": 1,
    "Sold": 1
  },
  {
    "Number": 2,
    "Title": "The lady in red",
    "Size": "70x50cm",
    "Paint": 1,
    "Sold": 0
  }]

    return (
            <main>
                <div className='left-main'>
                    <header className='top-section'>
                        <h3 className='top-section-text'>Select a painting:</h3>
                    </header>
                    <div className='painting-list'>
                        {images.map(block => Paintings(block))}
                    </div>
                </div>
                <div className='right-main'>
                    <div className='gallery-image'>
                        // DISPLAY image here based on variable from Paintings
                    </div>
                </div>
            </main>
    )
}

Simplified Child Component:

export default function Block(props) {

    return (
        <div className='painting-list-item' key={props.Number} value={props.number}>
            <div className='title-list-item'>
                <h2>{props.Title}</h2>
            </div>
            <div className='sold-list-item'>
                <p className={`${props.Sold ? "sold" : "not-sold"}`}>{props.Sold ? 'Sold' : 'Available'}</p>
            </div>
            <div className='size-list-item'>
                <p>{props.Size}</p>
            </div>
            <div className='image-list-item'>
                <img className="painting-list-item-img" src={`/images/${props.Number}.jpg`} width={50} height={50}/>
            </div>
        </div>
    )
}

Hopefully you guys can point me in the right direction, thank you in advance!

2

Answers


  1. I think at first in your .map function you want to define your components as <Paintings { ...block /> instead of Paintings(block) furthermore the way to pass which card is clicked with which index is by passing a function so create a function like onDelete(index) { console.log(index) } and pass this to the component like <Paintings { ...block } onDelete={ onDelete } /> now it is passed as a prop and within the Paintings component you can call this with the index that is passed to the block so like onDelete(props.Index) and it will call the function in the parent component.

    Login or Signup to reply.
  2. I would create some kind of state to track which painting should be displayed. And a derived variable which will hold the currently selected painting.

    const [activePaintingId, setActivePaintingId] = useState(null);
    
    const currentPainting = images.find(
      (image) => image.Number === activePaintingId
    );
    

    Then the first option could be to wrap the Paintings into a div element and applying a onClick there.

    <div className="painting-list">
      {images.map((block) => (
        <div onClick={() => setActivePaintingId(block.Number)}>
          <Paintings {...block} />
        </div>
      ))}
    </div>
    

    Where you then have access to the current painting like so.

    <div className="gallery-image">
      {activePaintingId !== null ? (
        // DISPLAY image here based on variable from Paintings
      // {currentPainting}
      ) : null}
    </div>
    

    The second one is to pass the function down to the child if you don’t want to have another div surrounding your paining.

    <div className="painting-list">
      {images.map((block) => (
        <Paintings {...block} setActivePaintingId={setActivePaintingId} />
      ))}
    </div>
    

    Then in the child add the onClick

    export default function Paintings(props) {
      return (
        <div
          className="painting-list-item"
          key={props.Number}
          value={props.number}
          onClick={() => setActivePaintingId(props.Number)}
        >
          ...
        </div>
      );
    }
    

    And displaying the image will be the same.

    Also you should not set a value prop on a div since value is not a valid attribute, see MDN div attributes.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search