Search code examples
javascriptcssreactjsmouseevent

Why I am not able to set the style inside the function of mouse event handler inside React component?


My code below: I am learning ReactJS. Trying to change the background colour of the button on mouse hover. I know css:hover is the easiest approach. But doing this implementation to learn.

It works fine if I check the 'hover' value using if else condition. But it gives the error "TypeError

Cannot assign to read only property 'backgroundColor' of object '#'" when I try to set the background colour inside the onMouseEnter and onMouseLeave event handler functions.

What is the read-only property here? I have not made it const. Is it read-only by default? How do I override it?


import React, { useState } from "react";
 
function App() {
  
  let [ hover, setState] = useState(false);
 
  let buttonStyle = {
    backgroundColor:''
  }
 
  function hoverActive(){
    setState(true);    
    buttonStyle.backgroundColor='black';
  }
 
  function hoverInactive(){
    setState(false);    
    buttonStyle.backgroundColor='';    
  }
 
  if(hover){
    //buttonStyle.backgroundColor='black';    
  }
  else{
    //buttonStyle.backgroundColor='';    
  }
 
  return (
    <div className="container">
      <h1>Hello</h1>
      <input type="text" placeholder="What's your name?" />
      <button style={buttonStyle} onMouseEnter={hoverActive} onMouseLeave={hoverInactive}>Submit</button>
    </div>
  );
}
 
export default App;

Solution

  • Few ways to achieve what you want:

    Using useState hook

    The issue you have now in your code is buttonStyle not being a state and React just ignores the changes you make to that variable.

    function App() {
      let [hover, setState] = React.useState(false);
    
      function hoverActive() {
        setState(true);
      }
    
      function hoverInactive() {
        setState(false);
      }
    
      return (
        <div className="container">
          <h1>Hello</h1>
          <input type="text" placeholder="What's your name?" />
          <button
            style={{
              backgroundColor: hover ? "black" : "",
              color: hover ? "white" : "black"
            }}
            onMouseEnter={hoverActive}
            onMouseLeave={hoverInactive}
          >
            Submit
          </button>
        </div>
      );
    }
    
    ReactDOM.render(<App />, document.querySelector('.react'));
    <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 class='react'></div>

    Using React refs

    You can achieve it using a React ref (using useRef hook for your function component):

    function App() {
      const buttonRef = React.useRef(null);
    
      function hoverActive() {
        buttonRef.current.style.backgroundColor = "black";
        buttonRef.current.style.color = "white";
      }
    
      function hoverInactive() {
        buttonRef.current.style.color = "black";
        buttonRef.current.style.backgroundColor = "";
      }
    
      return (
        <div className="container">
          <h1>Hello</h1>
          <input type="text" placeholder="What's your name?" />
          <button
            ref={buttonRef}
            onMouseEnter={hoverActive}
            onMouseLeave={hoverInactive}
          >
            Submit
          </button>
        </div>
      );
    }
    
    ReactDOM.render(<App />, document.querySelector('.react'));
    <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 class='react'></div>

    Using CSS

    function App() {
      return (
        <div className="container">
          <h1>Hello</h1>
          <input type="text" placeholder="What's your name?" />
          <button id="my-button">Submit</button>
        </div>
      );
    }
    
    ReactDOM.render(<App />, document.querySelector('.react'));
    #my-button:hover {
      background-color: black;
      color: white;
    }
    <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 class='react'></div>