Moving a mouse from one element to another does not reset its state

Link to code: https://codesandbox.io/s/objective-darwin-w0i5pk?file=/src/App.js

Description: There are four gray squares in this example, each with a different shade of gray. The goal is to change the background color of each square when the user hovers over them, increasing the RGB value by 10.

Issue: The problem arises when moving the mouse from one square to another; the initial square does not revert back to its original color state.

Help Needed: Could someone clarify why this is happening and provide guidance on how to resolve it as I'm unsure of the solution?

Note: I am attempting to achieve this without using CSS for hover effects, instead specifying the backgroundColor through JavaScript

import React, { useState } from "react";
import "./styles.css";

const tabs = [
  { name: "1", img: [] },
  { name: "2", img: [] },
  { name: "3", img: [] },
  { name: "4", img: [] }
];

const initialState = {};

tabs.forEach((t, i) => {
  initialState[i] = false;
});

export default function App() {
  const [hover, setHover] = useState(initialState);

  return (
    <div className="App">
      {tabs.map((t, i) => {
        const v = 50 - (i + 1) * 10;
        const val = hover[i] ? v + 10 : v;

        return (
          <div
            key={t.name}
            className="tab"
            onMouseOver={() => {
              setHover({
                ...hover,
                [i]: true
              });
            }}
            onMouseLeave={() => {
              setHover({
                ...hover,
                [i]: false
              });
            }}
            onMouseOut={() => {
              setHover({
                ...hover,
                [i]: false
              });
            }}
            style={{
              backgroundColor: `rgb(${val}, ${val}, ${val})`,
              height: "100px",
              width: "100px"
            }}
          >
            <p>{t.name}</p>
          </div>
        );
      })}
    </div>
  );
}
.App {
  font-family: sans-serif;
  text-align: center;
  margin: 0;
  padding: 0;
}
* {
  margin: 0;
  padding: 0;
}

Initial State Image:

Answer №1

setState is not executed immediately in React. The calls to the state setter are queued internally, which may lead to unexpected behavior. For example:

const [state, setState] = useState(0)

// somewhere

setState(state + 1)
setState(state + 1)

In this scenario, instead of ending up with 2, you will get 1. This is because both calls to setState result in:

setState(1)
setState(1)

The same issue can occur with callbacks like in your code:

// enter
setState({ ...state, [i]: true })
// leave
setState({ ...state, [i]: false })

When both functions are called, they use the wrong previous state causing issues. To resolve this problem, you can use a different pattern for setState:

setState(prevState => prevState + 1)
setState(prevState => prevState + 1)

To address your specific case, try:

// enter
setState(prevState => ({ ...prevState, [i]: true }))
// leave
setState(prevState => ({ ...prevState, [i]: false }))

Answer №2

The reason for this issue is that you are retaining the previous values in your state. To resolve this, make sure to update it as follows:

onMouseOver={() => {
              setHover({
                [i]: true
              });
            }}
            onMouseLeave={() => {
              setHover({
                [i]: false
              });
            }}
            onMouseOut={() => {
              setHover({
                [i]: false
              });
            }}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error: jQuery is unable to access the property 'xxx' because it is undefined

While attempting to make a post request from the site to the server with user input data, I encountered an error message saying TypeError: Cannot read property 'vehicle' of undefined as the response. Here is the HTML and script data: <!DOCTY ...

Passing a selected value from the child to the parent component through state in React using hooks

I'm currently working on a Dropdown component that includes a select tag. When the user changes the value in the select, the state is updated to reflect the selected option. The StyledDropdown component is used for styling the select element. const D ...

Are the Material UI API documentation in need of an update?

Do you think the Material UI API documentation may be outdated? Is there another resource where we can find information on element preferences? For example, MenuList https://material-ui.com/api/menu-list/ includes a property called disablePadding to remov ...

The Axios request came back with a status code of 200, yet there was no actual data

Recently, I started exploring axios and encountered an issue when trying to send a post request with an authorization header. While the response data is successfully returned in Postman, I'm unable to view any response data in my browser. Can someone ...

Encountering a CORS policy issue while attempting to retrieve data from an API

I have been attempting to retrieve data from the DHL API, however, I keep encountering issues due to CORS policy blocking the request. Even though I have configured the CORS policy on my backend server, the error persists. What could be the issue? Here ...

Removing the blue border around a button upon being clicked

Whenever I press my button, an unexpected event occurs. Is there a solution to avoid this issue? Thank you for your help! :) ...

How do I access and read a map within an array from Firebase using ReactJS?

I have an array that contains a map with two values: title and content. https://i.stack.imgur.com/WLWVG.png I am trying to read all the values in the array as if it were a map. However, I have attempted this code without success. Can anyone assist me? {d ...

Can side effects be safely incorporated within the callback of the useState hook?

Consider this scenario: const [value, setValue] = useState(false); const setSomething = (val) => { setValue((prev) => { fn(); dispatch(action); // or any other side effect return prev + val; }); }; Is it acceptable and in line with ...

Guide on extracting JSON data from specific nodes using d3.js

Just starting out with d3.js and following the example of a simple molecule created by d3 at http://bl.ocks.org/mbostock/3037015. I have a couple questions: 1. How can I select multiple nodes within the molecule structure? 2. Once selected, how do I ext ...

Do we need to include href in the anchor tag?

Why am I unable to display the icon within the <anchor> element without using the href attribute? The icon only appears when I set the href attribute to "". Even if I manage to show the icon by adding href="", adjusting the size with width and height ...

Exploring authentication in Next.js tutorial - tackling the issue of unwanted full page reload post successful login

Currently, I am constructing a website based on the guidance provided in this tutorial: https://nextjs.org/learn/dashboard-app/ Within the tutorial, there is a specific segment that can be found here: https://nextjs.org/learn/dashboard-app/adding-authenti ...

Using array.map() in React does not display elements side by side within a grid container

I'm currently working with React and material-ui in order to achieve my goal of displaying a grid container that is populated by an array from an external JavaScript file. The challenge I am facing is getting the grid to show 3 items per row, as it is ...

Setting a menu item as active in a SvelteKit app: A step-by-step guide

I encountered an issue with the main navigation menu in my sveltekit application. The problem is that when the app is loaded or refreshed, the active menu item corresponding to the current URL is not set. After struggling to find a solution online, I manag ...

What is the best way to prevent a decrease from reaching zero in React when using the useState hook?

Currently, I am developing a simplistic card-battle style game using React. In this game, the useState hook is utilized to dynamically render the HP of selected characters. However, there is an issue where the opponent's HP can go negative instead of ...

Requiring addresses for Google Maps in order to display directions

To display the directions between two addresses based on the chosen transportation mode, I need to pass the addresses to the code in page 2. After the user selects two cities from a Dropdown box on page 1, they will be sent to the code to show their locati ...

Leverage useSWR with personalized data for a logged-in user

When utilizing SWR to retrieve data for the logged-in user, I am unsure of the correct approach. For example, if I want to access data from the api endpoint api/get/cards specifically for the current user. If I use api/get/cards as the key in SWR, wouldn& ...

We regret to inform you that the Serverless Function in NextJs has surpassed the maximum size limit of 50mb

Recently, I've started working with NextJs and encountered an issue while attempting to deploy my project on Vercel. The error message that popped up looked like this: Error! The Serverless Function "api/auth" exceeds the maximum size limit of 50mb, ...

Switch between dropdowns with jQuery

Issue at Hand: In the scenario illustrated below, there is a side navigation bar containing options that reveal a toggled section upon clicking. Specifically, if you select the third item labeled "Dolar" from the menu, a dropdown with three additional cho ...

The alignment of the navigation menu disrupts the functionality of the dropdown sub-menus

I'm finding it challenging to center the navigation menu while maintaining the functionality of the drop-down li elements. Here is my demo: http://jsbin.com/tosayosino/1/edit?html,css,js,output Removing the float:left; property from .jetmenu li succ ...

Unable to establish a new pathway in the index.js file of a Node.js and Express website running on Heroku

I recently made some changes to my index.js file: const express = require('express'); const path = require('path'); const generatePassword = require('password-generator'); const fetch = require('node-fetch'); const ...