简体   繁体   中英

React class does not update when state changes

I am making a game where I need different style for selected (pressed) item. I am trying to attach "selected" class to div if that div is clicked. In other words, I have a state:

const [pressedGifId, gifPressed] = useState(null);

and when

pressedGifId === gifId

then I should attach "selected" class to my div. Here is my simplified code:

import React, { useState, useEffect } from 'react';

export default function Game() {
  const addedToGameGif = [];

  const [pressedGifId, gifPressed] = useState(null);
  const [photoCards] = useState([]);

  useEffect(() => {
    console.log(pressedGifId);
  }, [pressedGifId]);

  if (photoCards.length === 0) {
    for (let i = 0; i < 5; i += 1) {
      addedToGameGif.push([i, 'http://petapixel.com/assets/uploads/2019/06/manipulatedelephant-800x534.jpg']);
    }
  }

  addedToGameGif.map(item =>
    photoCards.push(
      <div key={item[0]}>
        <div
          onClick={() => gifPressed(`gif${item[0]}`)}
          className={`${pressedGifId === `gif${item[0]}` && 'selected'}`}
        >
          <img src={item[1]} alt="bla" width="300" height="180" />
        </div>
        <br />
      </div>,
    ),
  );
  return <div>{photoCards}</div>;
}

I can't see class updated accordingly to state: (it stays null)

f12 视图

But I get updated state in console ( I print it in useEffect):

控制台视图

My goal:

1) Change state (pressedGifId) on click

2) Add class "selected" to div if pressedGifId matches currently mapped item id ( gif${item[0]} )

UPDATE2 :

Providen solution werent working for me since my photoCards were randomly picked photos and with provided solutions photos were changing into new randomly picked photos on every click (which I dont want to be). But it led me to the correct answer:

I put photoCards into a state (a hook) and set it on a first load (when photoCards array length is 0). It prevented from reloading and classes worked.

Here is updated code:

    export default function Game(props) {

    const [pressedGifId, setGifPressed] = useState(null);
    const [gifCards, setGifCards] = useState([]);

    useEffect(() => {
        if (gifCards.length === 0) 
          setGifCards(randGen.getGifArray());
    }

      const renderCards = () =>
      gifCards.map((item, index) => {
      const gifId = `gif${item[0]}`;

      return (
        <div key={item[0]}>
          <div
            onClick={() => setGifPressed(gifId)}
            onKeyPress={() => setGifPressed(gifId)}
            role="button"
            tabIndex="0"
            className={`card ${getClass(gifId)}`}
          >
            <img
              src={item[1]}
              alt={txtCards[index][1]}
              width="300"
              height="180"
            />
          </div>
        </div>
      );
    });

     return (
       <div>
          {renderCards()}
        </div>
      );
   }



import React, { useState, useEffect } from 'react';

const Game = () => {

  //here we are passing our gif data 
  const gifData = [
    'http://petapixel.com/assets/uploads/2019/06/manipulatedelephant-800x534.jpg',
    'http://petapixel.com/assets/uploads/2019/06/manipulatedelephant-800x534.jpg',
    'http://petapixel.com/assets/uploads/2019/06/manipulatedelephant-800x534.jpg',
    'http://petapixel.com/assets/uploads/2019/06/manipulatedelephant-800x534.jpg',
    'http://petapixel.com/assets/uploads/2019/06/manipulatedelephant-800x534.jpg' 
  ]

  // pressedGifId : for gifId selection
  const [pressedGifId, setGifPressed ] = useState(0);

  // renderPhotoCards : this function return all cards 
  // onClick :   setGifPressed to clicked gifId 
  // className : if our index of perticuler gif match with pressedGifId then we are setting it as selected

  const renderPhotoCards = () => 
    gifData.map(( item , index )  => (
      <div key={index}>
        <div
          onClick={() => setGifPressed(index)}
          className={  pressedGifId === index ? `gif${index} selected` : `gif${index}`  }
        >
          <img src={item} alt="bla" width="300" height="180" />
        </div>
        <br />
      </div>
    )
  )

  return renderPhotoCards()

}

export default Game;

This is the line where I changed.

className={pressedGifId === `gif${item[0]}` ? "selected" : ""}

The entire code.

import React, { useState, useEffect } from "react";
import "./styles.css";
export default function Game() {
  const addedToGameGif = [];

  const [pressedGifId, gifPressed] = useState(null);
  let photoCards = [];

  useEffect(() => {
    console.log("->", pressedGifId);
  }, [pressedGifId]);

  if (photoCards.length === 0) {
    for (let i = 0; i < 5; i += 1) {
      addedToGameGif.push([
        i,
        "https://petapixel.com/assets/uploads/2019/06/manipulatedelephant-800x534.jpg"
      ]);
    }
  }

  photoCards = addedToGameGif.map(item => (
    <div key={item[0]}>
      <div
        onClick={() => gifPressed(`gif${item[0]}`)}
        className={pressedGifId === `gif${item[0]}` ? "selected" : ""}
      >
        <img src={item[1]} alt="bla" width="300" height="180" />
        {console.log(item)}
      </div>
      <br />
    </div>
  ));

  console.log("-", photoCards, addedToGameGif);
  return <div>{photoCards}</div>;
}

This is working. I tried, check this JS snippet

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