0

So, first of all, what I'm trying to do is the following: I have a few divs that contain some text and an image. All the data for the divs is stored in a state array. You can also add divs and delete whichever div you desire. What I would like to implement now, is to change the picture when the user clicks on an image. There is a preset image library and whenever the user clicks on the image, the next image should be displayed.

Here is some relevant code:

let clicks = 0;
class Parent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data : [
                createData( someimage, "Image 1"),
                createData( anotherimage, "Image 2"),
                createData( thirdimage, "Image 3"),
                createData( fourthimage, "Image 4"),
             ],
        imgs : [imgsrc1,imgsrc2, imgsrc3, imgsrc4],
        }
    }

newIcon (n) {
    let newStateArray = this.state.data.slice();
    let newSubStateArray = newStateArray[n].slice();

        if(clicks === 1) {

            newSubStateArray[0] = this.state.imgs[0];
            this.setState({imgsrc:newSubStateArray});
            clicks++;
        } else if (clicks === 2) {

            newSubStateArray[0] = this.state.imgs[1];
            this.setState({imgsrc:newSubStateArray});
            clicks++;
        } else if (clicks === 3) {

            newSubStateArray[0] = this.state.imgs[2];
            this.setState({imgsrc:newSubStateArray});
            clicks++;
        } else if (clicks === 4) {

            newSubStateArray[0] = this.state.imgs[4];
            this.setState({imgscr:newSubStateArray});
            clicks++;
        } 
    }           

render () {
    let { data }= this.state;
    return(
        <div>

            {data.map((n) => {
                return(
                <Child imgsrc={n.imgsrc} key={n} newIcon={this.newIcon.bind(this, n)} header={n.header} />
                );
            })}

        </div>
    );
}

A few sidenotes: createArray is a function to create the sub-arrays and can probably be ignored for this question. What is important to know is, that the first element is called imgsrc, and the second element is called

So, something is going wrong here but I'm not sure what it is exactly. My guess is, that I'm not properly accessing the values within the arrays. Above, you can see that I tried to slice the arrays and to then allocate the new value. Another problem I've encountered, is that n comes up as undefined, when I try to call it from my newIcon()-function. I'm kind of lost here, as I'm quite new to React so any sort of hints and suggestions are welcome.

2 Answers 2

1

I would do away with all that code in newIcon, and keep clicks as part of the state. If you have an array of images then you can use clicks as a pointer to the next image that should be shown.

In this example I've taken the liberty of adding in dummy images to help explain, and changed clicks to pointer as it makes more sense.

class Parent extends React.Component {

  constructor(props) {
    super(props);
    this.state = {

      // clicks is called `pointer` here and initially
      // is set to the first index of the imgs array
      pointer: 0,
      imgs: [
        'https://dummyimage.com/100x100/000000/fff.png',
        'https://dummyimage.com/100x100/41578a/fff.png',
        'https://dummyimage.com/100x100/8a4242/fff.png',
        'https://dummyimage.com/100x100/428a49/fff.png'
      ]
    };

    // Bind your class method in the constructor
    this.handleClick = this.handleClick.bind(this);
  }

  // Here we get the length of the imgs array, and the current
  // pointer position. If the pointer is at the end of the array
  // set it back to zero, otherwise increase it by one.
  handleClick() {
    const { length } = this.state.imgs;
    const { pointer } = this.state;
    const newPointer =  pointer === length - 1 ? 0 : pointer + 1;
    this.setState({ pointer: newPointer });
  }

  render() {

    const { pointer, imgs } = this.state;

    // Have one image element to render. Every time the state is
    // changed the src of the image will change too.
    return (
      <div>
          <img src={imgs[pointer]} onClick={this.handleClick} />
      </div>
    );
  }

}

DEMO

EDIT: Because you have more than one div with images the sources of which need to change, perhaps keep an array of images in a parent component and just pass a subset of those images down to each Image component as props which you then store in each component's state. That way you don't really need to change the Image component that much.

class Image extends React.Component {

  constructor(props) {
    super(props);
    this.state = { pointer: 0, imgs: props.imgs };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    const { length } = this.state.imgs;
    const { pointer } = this.state;
    const newPointer =  pointer === length - 1 ? 0 : pointer + 1;
    this.setState({ pointer: newPointer });
  }

  render() {

    const { pointer, imgs } = this.state;

    return (
      <div>
          <img src={imgs[pointer]} onClick={this.handleClick} />
      </div>
    );
  }

}

class ImageSet extends React.Component {

   constructor() {
     super();
     this.state = {
       imgs: [
        'https://dummyimage.com/100x100/000000/fff.png',
        'https://dummyimage.com/100x100/41578a/fff.png',
        'https://dummyimage.com/100x100/8a4242/fff.png',
        'https://dummyimage.com/100x100/428a49/fff.png',
        'https://dummyimage.com/100x100/bd86bd/fff.png',
        'https://dummyimage.com/100x100/68b37c/fff.png',
        'https://dummyimage.com/100x100/c9a7c8/000000.png',
        'https://dummyimage.com/100x100/c7bfa7/000000.png'
      ]
     }
   }

   render() {

     const { imgs } = this.state;

     return (
       <div>
         <Image imgs={imgs.slice(0, 4)} />
         <Image imgs={imgs.slice(4, 8)} />
       </div>
     )
   }

}

DEMO

Hope that helps.

Sign up to request clarification or add additional context in comments.

3 Comments

thank you very much for your answer! I have several divs with pictures all of which should be able to change images, meaning I would have to access an array within another array. Do you know how I would do that in this case because I can't seem to figure out how to adapt your answer in that way. I have an array of images which i use in an array of divs to display them dynamically
thank you so much, it works for me! Just one last question, I generate the div that contain the images dynamically and I'm not sure how to set the initial picture. For the first div I want img1, for the second div img2, for the third div img 3 and so on, do you know how I would do that?
Sure. Just arrange the image array in the way you need, perhaps an array of arrays, and then just pass each nested array down to the component that's creating the div. There are lots of different ways to approach it. Just experiment a little and find the one that suits your style @A.S.J
0

Try to bind the newIcon() method in the constructor, like this :

this.newIcon = this.newIcon.bind(this);

and in the render method call it normally without any bind :

this.newIcon(n)

4 Comments

ah unfortunately that happened while I copy&pasted my own code and deleted all parts not relevant for this question. Thank you for the hint, I'll fix it immediately
Yes, it is recommended to bind it in the constructor, also, i think the right way to bind it there is this.newIcon(n).bind(this)
You are passing n to the binding method, not to newIcon method.
unfortunately, that did not fix it either though

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.