2

The onCardLeftScreen event handler triggers the console log function but doesn't update state using the setState hook? I have tested that this is the issue with an onClick function which runs as intended.

React code:

//sets initial cards within the queue
  const [cardQueue, setCardQueue] = useState([Data[0], Data[1], Data[2]]);

  //sets the index of card that will be pushed into queue
  const [cardQueueLength, setCardQueueLength] = useState(Data.length - 1);

  const autoplayChange = () => {
    setSlideShow(!slideShow);
    console.log("playing!");
  };

  const CardLeftScreen = () => {
    //iterates through cards(sets up loop)
    setCardQueueLength(
      cardQueueLength < Data.length - 1 ? cardQueueLength + 1 : 0
    );

    //removes card from front of queue
    cardQueue.shift();

    //pushes a card to back of queue
    cardQueue.push(Data[cardQueueLength]);

    //sets slideshow to true
    setSlideShow(true);

    //console logs cards in arrays and the index of the card being pushed to back of queue
    console.log(cardQueue);
    console.log(cardQueueLength);
  };

  return (
    <div className="cardStyles">
      {cardQueue.map((Projects, index) => {
        return (
          <TinderCard
            key={Projects.workName}
            preventSwipe={["up", "down"]}
            onCardLeftScreen={CardLeftScreen}
            className="Cards"
          >
            <Carousel
              showThumbs={false}
              infiniteLoop={true}
              swipeable={false}
              emulateTouch={false}
              showStatus={false}
              autoPlay={slideShow}
              dynamicHeight={false}
            >
              <div className="image-iframeContainer">
                {Projects.Images &&
                  Projects.Images.map((Image, index) => {
                    return (
                      <div key={Image} className="image-iframeContainer">
                        <img alt="Images of web apps" src={Image} />
                      </div>
                    );
                  })}
              </div>
            </Carousel>
            <h1>{Projects.workName}</h1>
            {Projects.workTech.map((Tech, index) => {
              return (
                <p key={Tech} className="techList">
                  {Tech}
                </p>
              );
            })}
            <div className="descriptionContainer">
              <p className="description">{Projects.workDescription}</p>
            </div>
          </TinderCard>
        );
      })}
      <button className='cardLeftScreenButton' onClick={CardLeftScreen}>click for onCardLeftScreen desired funtion</button>
    </div>
  );

I have also set up a Sandbox to better display my issue, Hopefully, someone can find a solution my project is so nearly finished. the API used is React-Tinder-Card

lukeet
  • 341
  • 1
  • 10
  • 1
    You are mutating state directly with `.shift()`. You should not be affecting the `cardQueue` object directly. – zero298 Sep 26 '20 at 20:37
  • Does this answer your question? [Delete item from state array in react](https://stackoverflow.com/questions/36326612/delete-item-from-state-array-in-react) – zero298 Sep 26 '20 at 20:45

4 Answers4

1

whenever you set state in function it doesnt update immediately you can see the change only after event handler comes out of the function.

I think your code is correct and try console log after the function it will show you the intended result and if want to use the updated value use a variable like below

 const CardLeftScreen = () => {
        //iterates through cards(sets up loop)
        let p=
          cardQueueLength < Data.length - 1 ? cardQueueLength + 1 : 0
        

        //removes card from front of queue
        cardQueue.shift();

        //pushes a card to back of queue
        cardQueue.push(Data[p]);

        //sets slideshow to true
        setSlideShow(true);
        
        setCardQueueLength(p);
        //console logs cards in arrays and the index of the card being pushed to back of queue
        console.log(cardQueue);
        console.log(cardQueueLength);
      };
      
          console.log("you can see the change here",cardQueueLength);//you can see the change here
  • Just tested it out works the same as my example in the sand box works onClick but not when a card is swiped, thanks though! – lukeet Sep 27 '20 at 13:47
1

You are mutating your state array directly instead of duplicating it and affecting that array. This means that React doesn't think your array has actually changed. Consider the change below:

const {useState} = React;

const mockData = [
    {title: "Foo", description: "Hello World!"},
    {title: "Bar", description: "Fizz Buzz!"},
    {title: "Cool", description: "More Stuff!"}
];

const MyComponent = () => {
    const [cards, setCards] = useState([mockData[0], mockData[1], mockData[2]]);
    const [nextDataIndex, setNextDataIndex] = useState(mockData.length - 1);

    const onCardLeftScreen = () => {
        const newNextDataIndex = nextDataIndex < mockData.length - 1 ? nextDataIndex + 1 : 0;

        const newCards = [...cards];
        newCards.shift();
        newCards.push(mockData[newNextDataIndex]);

        setNextDataIndex(newNextDataIndex);
        setCards(newCards);
    };

    return (
        <div>
            <div>Num cards: {cards.length}</div>
            <div className="card-container">
                {cards.map(card => (
                    <div key={card.title} className="card">
                        <div>{card.title}</div>
                        <div>{card.description}</div>
                    </div>
                ))}
            </div>
            <button onClick={onCardLeftScreen}>Swipe Left</button>
        </div>
    );
};

const App = () => (
    <MyComponent />
);

ReactDOM.render(
    <App/>,
    document.getElementById("app")
);
.card-container {
  width: 100px;
  height: 100px;
  position: relative;
}
.card {
  background-color: #0000AA;
  color: #ffffff;
  padding: 0.2em;
  width: 50px;
  height: 50px;
  box-shadow: 2px 2px black;
  position: absolute;
  top: 0;
  left: 0;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="app"></div>
zero298
  • 20,481
  • 7
  • 52
  • 83
  • While your code does work perfectly onClick its still not working when the cards are swiped, if you go into my sandbox you can swipe the cards and press the button and see the different outcomes, thank you though your code is much better – lukeet Sep 27 '20 at 14:01
1

Try something like this. You are mutating state directly which is not good and can lead to all sorts of side effects and mishaps, and maybe the reason you might see the same cards twice in a row, lag, etc.

  // sets initial cards within the queue
  const cards = [ Data[0], Data[1], Data[2] ];
  const [cardQueue, setCardQueue] = useState(cards);
  const [cardQueueLength, setCardQueueLength] = useState(Data.length - 1); //sets the index of card that will be pushed into queue

  const autoplayChange = () => {
    setSlideShow(!slideShow);
    console.log("playing!");
  };

  //iterates through cards(sets up loop)
  const handleCardLeave = () => {
    const newCardQueueLength = cardQueueLength < Data.length - 1 ? cardQueueLength + 1 : 0;
    setCardQueueLength(newCardQueueLength);

    const updatedCardQueue = [...cardQueue]; // don't mutate state directly
    updatedCardQueue.shift(); // removes card from front of queue
    updatedCardQueue.push(Data[cardQueueLength]); // pushes a card to back of queue
    setCardQueue(updatedCardQueue);

    //sets slideshow to true
    setSlideShow(true);

    //console logs cards in arrays and the index of the card being pushed to back of queue
    console.log(cardQueue);
    console.log(cardQueueLength);
  };
Ross Sheppard
  • 757
  • 1
  • 4
  • 12
  • Thanks mate this is very nice code and I tried it in my project but if you check out the sandbox on swipe I'm still getting the same issue? – lukeet Sep 27 '20 at 14:03
  • Did you try passing the `handleCardLeave` function to the `onSwipe` property of TinderCard instead of `onCardLeftScreen`? I can update the answer if that's the desired effect. – Ross Sheppard Sep 27 '20 at 17:43
1

The issue was caused due to the fact that the key used was not unique, the onClick function causes react to refresh updating the Dom whereas the onCardLeftScreen function doesn't by default. Setting the key of the Tindercard to key={Projects.workName + Math.random()} fixes the issue as react knows when to refresh. Thanks, everyone for pointing out the state mutation it didn't fix my problem but certainly made my code cleaner

lukeet
  • 341
  • 1
  • 10