Image gallery in React, how to select the active image and reflect only on the component itself?

Asked

Viewed 175 times

0

Save guys! No bullshit, follow the gif to get a sense of the problem: error

My list of items is being pulled from a JSON, where in the listing of all my items I made a map().

const [imageSrc, setImageSrc] = useState({});

  const handleImageSrc = (e) => {
    e.preventDefault();

    // url da imagem ao clicar
    setImageSrc(e.target);
    
  };
<>
  {data.map((dataItem) => {
   **// data = imagens, descrição e valores.**
    return (
      <>
        <Paper className="paperContainer">
          <Grid container wrap="nowrap" spacing={3}>
            <Grid item xs={2}>
              <Paper>
                <ul className="imgList">
                 
                **//map de todas as imagens, e a lista lateral**

                  {dataItem.product.images.map((image) => {
                    return (
                      <li key={image.id}>
                        <a href={image}>
                          <img
                            // todas as imagens tem a função handleImageSrc para pegar o url
                            onClick={handleImageSrc}
                            src={image}
                            alt={dataItem.product.name}
                            onError={(e) => { e.target.onerror = null; e.target.src = 'https://ik.imagekit.io/b0g9wlasxh/buscape-images/images_ZDQgkWoQc.png'; }}
                          />
                        </a>
                      </li>
                    );
                  })}

                </ul>
              </Paper>
            </Grid>
            <Grid item xs={4}>
              <Paper className="imgList">

              **// imagem que eu preciso refletir no componente atual ao cllicar.**
                // coloquei o imageSrc direto na imagem que vai ser alterada, que no caso seria bem previsível o erro, porém fica melhor de exemplificar. 
                <img
                  src={imageSrc.src
                    ? imageSrc.src
                    : dataItem.product.images[0]}
                  alt={imageSrc.alt}
                />

              </Paper>
            </Grid>
            <Grid item xs={5}>
              <Paper className="imgList">
                <h2>{dataItem.product.name}</h2>
                <h3>Better price</h3>
                <div className="priceValue">
                  <span className="value">10x R$ 134,11</span>
                  <button type="button" className="cardAdd">
                    Adicionar ao carrinho
                  </button>
                </div>
                ou
                {' '}
                <span className="greenValue">R$ 1.139</span>
                {' '}
                à vista
              </Paper>
            </Grid>
          </Grid>
        </Paper>
      </>
    );
  })}
</>

Because I am making a map and placing the handleImageSrc function for all images, the stored image url will reflect on all components.

One thing I thought, was to take the current component of the image I clicked on, and look for the daughter div (where is the larger image that will be reflected).

Someone could give me a hint and hints of what to do in this situation?

  • 1

    You’re using a state for all images, so you change, changes at all. I think the ideal would be to create a new component that would be paper, then each component would have its own state, and you pass the image, title and menu via props. ai on the map you generate this component every time

  • Thanks Marcos! You just clear my ideas. I’ll try to tidy up and Aja come back here.

  • I came back here to say that it worked! Thank you so much for helping me, now that I’ve solved I feel like a fool for not thinking about it before

1 answer

0

Well I imagine that it is a product registration and inside has a list of images where the first image will appear as default and to the left the list of images of this product, when clicking is selected the image and shown the photo of the respective item, example:

function App() {
  const [products, setProducts] = React.useState([
    {'id': 1, 'name': 'produto 1', 'photos': [
      'http://placeimg.com/150/150/animals',
      'http://placeimg.com/150/150/nature'
    ], 'default': ''},
    {'id': 2, 'name': 'produto 2', 'photos': [
      'http://placeimg.com/150/150/sepia',
      'http://placeimg.com/150/150/people'
    ], 'default': ''}
  ]);  
  const setImagem = (e, id) => {
    const { src } = e.target;
    const newProducts = products.map(p => {
      if (p.id !== id) return p;
      return {...p, 'default': src };
    });
    setProducts(state => [...newProducts]);
  }
  return (
    <div>
      <div className='row'>
      {products.length && products.map((p,i) => {
        return (
          <React.Fragment>          
          <div className='col-6'>
            {p.photos.map((f,c) => 
              (<img src={f} key={c} className='mb-3 ml-3'
              onClick={e => setImagem(e, p.id)} style={{cursor: 'pointer'}} />) 
            )}
          </div>
          <div className='col-6'>
            <h4>{p.name}</h4>
            <img src={p.default || p.photos[0]} key={i} className='mb-3' />
          </div>
          <div className='col-12'><hr/></div>
          </React.Fragment>
        )
      })}
      </div>
    </div>
  );
}
ReactDOM.render( <App/> , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"/>
<div id="root"></div>

When clicking the photo the photo is shown in your product respectively and an additional field with the name 'default' was created to put the chosen photo, this is a simple example to understand the separation of each product.

  • Thanks little brother, I got it all figured out.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.