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:

https://i.sstatic.net/m6vpc.png

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

to return the value to default when deactivating the text input field

Implementing typeahead functionality on two input fields: <div class="form-group> <label class="control-label=">Product Code:</label> <input placeholder="Enter Value" type="text" class="form-control" ng-model="a.product ...

Aligning Font Awesome icons inside md-buttonsFinding the perfect alignment for

I am attempting to center font awesome icons within a button so that they align perfectly with the text on a toolbar. Below is the code snippet I am working with: <div ng-app="app"> <md-toolbar> <div class="md-toolbar-tools" md-tall ...

Global usage of makeStyles - useStyles() results in 'Invalid Hook Call' error

I am encountering the 'Invalid hook error' while trying to implement this example from Material UI's website: https://material-ui.com/styles/advanced/#GlobalCss.js import React from 'react'; import { makeStyles } from '@materi ...

Utilize Javascript to conceal images

On a regular basis, I utilize these flashcards. Recently, I have started using images as answers. However, I am facing an issue - I am unable to conceal the pictures. My preference is for the images to be hidden when the webpage loads. function myShowTe ...

Adding a slight 1px right margin between an HTML table and its enclosing div in Bootstrap 3

Help! I'm trying to troubleshoot some HTML issues and can't figure out where this pesky 1px gap between my table and the wrapping div is coming from... Just for reference, I am using Bootstrap. I suspect that it could be a glitch in the Bootst ...

Implementing CKEditor instances within AngularJS Controller scopes

Greetings everyone, Recently, I have been exploring Angular JS. Everything is going smoothly - my controllers, services, and so on. However, when attempting to make a Div editable that is within the ng-controller, the ckeditor toolbar fails to appear. On ...

Utilizing unique background images tailored to different screen resolutions

In order to enhance the user experience on my website, I am looking to implement a feature that dynamically changes the background images based on the user's screen resolution. My plan is to use a small snippet of JavaScript within the <head> s ...

Exporting Data and Utilizing a Steady Data Table

I have incorporated the Fixed Data Grid into my latest project. https://facebook.github.io/fixed-data-table/example-sort.html My goal is to generate csv and pdf reports from the data displayed on the grid. Could you please advise me on how to export gri ...

The type 'any' cannot be assigned to the type 'never' as a parameter

const [files, setFiles] = useState([]) const handleChange = (event: any) => { setFiles.push(event.target.files[0].name) return (<div> {files.map((file: any) => ( <p>Hello!</p> ))} </ ...

Limit image size in Outlook when using Mailchimp

I'm currently working on coding a Mailchimp template for a client and I've run into an issue with image dimensions. The problem arises when images exceed the width of the template (usually 600px), as they are displayed at their original size in ...

When attempting to upload an image file to my backend server, I am facing the issue of receiving an empty object upon its arrival

I'm currently working on a form that captures an image, sends it to the backend, and then saves it to my local disk. However, I am encountering an issue where when I send the image file to the backend, it shows up as an empty object. Frontend import ...

You are unable to extract data from an HTML table

I have been encountering an issue while trying to extract data from an HTML table. Every time I attempt to do so, I am faced with an ERROR Message 13 "Type Mismatch". I suspect that the problem lies in my use of incorrect HTML tags. Despite spending severa ...

JSON parsing error within the HTML Sidebar list

I have a JSON file that contains data I need to parse in order to display information in my sidebar. When a user clicks the button labeled "List all sessions", the goal is to showcase all of the available session details grouped by Session ID and location. ...

How to efficiently center a jQuery Mobile Dialog on the screen using custom dimensions

I designed an app using jQuery Mobile and I'm looking to display a Dialog box when a button is clicked. The Dialog box should be centered on the screen with specified width and height. For reference, you can view the current version on jsfiddle. The ...

React and Rails are not playing nice when it comes to AJAX POST requests - all

I'm currently facing an issue while setting up this AJAX POST request in my react component to interact with my rails api controller. The browser console shows a 404 error and I am unable to trigger the pry debugger. react/src/pages/HomeIndex.js ge ...

Issue with displaying the second dropdown based on the selection made in the previous dropdown

I wanted to address a recurring issue that has been discussed in various posts, such as this one on Stack Overflow: Show a second dropdown based on previous dropdown selection Despite attempting numerous solutions suggested in those posts, I have not been ...

Optimizing Animation Effects: Tips for Improving jQuery and CSS Transitions Performance

Wouldn't it be cool to have a magic line that follows your mouse as you navigate through the header menu? Take a look at this example: It works seamlessly and smoothly. I tried implementing a similar jQuery script myself, but it's not as smoot ...

What size should I use for creating a responsive website?

After scouring the internet, I stumbled upon numerous dimensions referred to as proper for developing responsive designs. However, I am specifically interested in identifying the ideal breakpoints, particularly for mobile devices with small screens like ...

What sets @mui/material apart from @mui/system?

While using MUIv5, I came across this documentation link but I'm still confused about the disparity between @mui/material and @mui/system. Specifically, I am referring to their utility in utilizing the styled feature. It appears that they are used i ...

Difficulty with MultiHandleSliderExtender and postback in JavaScript

Attempting to implement the multihandlesliderextender (from the Ajax Toolkit) for creating a price filter option on a webshop. Upon selecting a new price, it should trigger a reload of everything including extensive behind-the-scenes code. Referenced an a ...