Home > Back-end >  Why I am not able to set the style inside the function of mouse event handler inside React component
Why I am not able to set the style inside the function of mouse event handler inside React component

Time:08-29

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 onm ouseEnter and onm ouseLeave 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} onm ouseEnter={hoverActive} onm ouseLeave={hoverInactive}>Submit</button>
    </div>
  );
}
 
export default App;

CodePudding user response:

It has to do with how object works in javascript. Refer.. Cannot assign to read only property 'name' of object '[object Object]'

You can take Reference of the object and use State or Ref to update the Background color.

import React, { useState } from "react";

function App() {
  let [hover, setState] = useState(false);

  let buttonStyle = {
    backgroundColor: "",
  };
  const [ButtonStyle, setButtonStyle] = useState(buttonStyle);

  function hoverActive() {
    setState(true);
    const data = { ...buttonStyle, backgroundColor: "green" };
    setButtonStyle(data);
  }

  function hoverInactive() {
    setState(false);
    const data = { ...buttonStyle, backgroundColor: "" };
    setButtonStyle(data);
  }

  return (
    <div className="container">
      <h1>Hello</h1>
      <input type="text" placeholder="What's your name?" />
      <button
        style={ButtonStyle}
        onm ouseEnter={hoverActive}
        onm ouseLeave={hoverInactive}
      >
        Submit
      </button>
    </div>
  );
}

export default App;

CodePudding user response:

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"
        }}
        onm ouseEnter={hoverActive}
        onm ouseLeave={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}
        onm ouseEnter={hoverActive}
        onm ouseLeave={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>

CodePudding user response:

buttonStyle does not cause the component to be re-rendered as a result the value cannot be updated or manipulated. A good approach would be the useState hook and update the state as needed

const [buttonStyle, setButtonStyle] = useState({ backgroundColor: '' })
const handleHover = () => {
   setState(!hover);

  if (hover) {
     setButtonStyle({ ...buttonStyle, backgroundColor: '#fff' });
  } else {
    setButtonStyle({ ...buttonStyle, backgroundColor: 'red' });
  }
};
<div className="container">
  <h1>Hello</h1>
  <input type="text" placeholder="What's your name?" />
  <button
    style={buttonStyle}
    onm ouseEnter={handleHover}
    onm ouseLeave={handleHover}
  >
    Submit
  </button>
</div>

I'm using the spread operator as its standard practice when setting object state. This does not mutate the original state. Best practice to name your setState based on what they do, e.g setButtonStyle, setHoveredOn

  • Related