简体   繁体   中英

React state gets resetted after rerendering

I am new to React and facing an issue with updating the state of a functional component.

I have a component TinderCards.js like below, which basically takes in a list of objects from a context provider and for each object, creates a TinderCard ( https://www.npmjs.com/package/react-tinder-card ) which is supposed to update the count when swiped ( onSwipe ).

However, what happens is that every time a card gets swiped, the count gets increased to 1 and then doesn't go any further.

Eg

Initial count value: 0

Swipe first card => count = 1

Swipe second card => count = 1 (should be 2)

Swipe third card => count = 1 (should be 3)

I have tried including the count value as both part of the Component's state and as part of a global context called ResultsContext.js , but both lead to the same behaviour.

NOTE that the button with class test-btn behaves EXACTLY how I want at onClick . However, the onSwipe for the TinderCard Component doesn't, even though it's basically the same code and it's driving me crazy.

TinderCards.js

import React, { useState, useEffect, useContext } from "react";
import TinderCard from "react-tinder-card";
import StocksContext from "./StocksContext";
import ResultsContext from "./ResultsContext";
import "./Tindercards.css";

function TinderCards(props) {
  // const [count, setCount] = useState(0);
  const { count, setCount } = useContext(ResultsContext);
  const { stocks, setStocks } = useContext(StocksContext);

  return (
    <div>
      <div className="tinderCards__cardContainer">
        <div>
          Count: {count}
          <button className="test-btn" onClick={() => setCount(count + 1)}>Increment</button>
        </div>
        <div className="main__container">
          {stocks.map((stock) => (
            <TinderCard
              onSwipe={() => setCount(count + 1)}
              className="swipe"
              key={stock.name}
              preventSwipe={["up", "down"]}
            >
              <div className="card">
                <div style={{ height: "100%" }}>
                  <img
                    src={stock.url}
                    style={{
                      objectFit: "contain",
                      height: "100%",
                      width: "100%",
                      backgroundColor: "white",
                    }}
                  />
                </div>
              </div>
              <h3 style={{ backgroundColor: "white" }}>${stock.name}</h3>
            </TinderCard>
          ))}
        </div>
      </div>
    </div>
  );
}

export default TinderCards;

I appreciate any help! Thank you very much!

Each count variable inside the onSwipe handler(s):

() => setCount(count + 1)

is a closure that contains the value of count at the point they were rendered - which is 0. One of those functions running doesn't actually change the value of the count variable - it simply triggers a rerender of the parent component. Those other children still retain their onSwipe handler that simply sets the count to 2 (1 more than the value of count when they were rendered) - which is what you're seeing.

The simple solution here is to pass an update function to setCount , rather than a hardcoded value:

onSwipe={() => setCount(prevCount => prevCount + 1)}

This will ensure that the "latest value" of the count state is always read, and incremented by 1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM