Home > Software design >  How to re-render only one component on hover when state changes in React
How to re-render only one component on hover when state changes in React

Time:02-16

There is an icon which says call is active, with classname "callConnect". When I hover on the icon, the icon should change, the new icon would be of classname "callDisconnect"

I am just writing a snippet to show my implementation which is not working:

I am using useRef and a functionto update

const hover = useRef(false)
const updateHoverState = (val: boolean) => {
   hover.current = val
}

In my component i have a method which renders the icon as so:

<div onm ouseOver={() => {
         updateHoverState(true)
         console.log("hovering", hover.current)}
     } 
     onm ouseOut={() => {
         updateHoverState(false)
         console.log("coming out", hover.current)}
     }
>
  {console.log("rendering", hover.current)}  //not working
  {hover.current ? <Icon onClick={() => { }} className={"callDisconnect"} /> : 
              <Icon  onClick={() => { }} className={"callConnect"} />}
</div>

When i run the code, the I see that hover is getting updated to true and false properly when I hover and move out, but the icons are not changing. Re-rendering is not happening. How to fix please help.

Please note: I have already tried using useState, since it did not work, I switched to useRef.

useState:

  const [hover, setHover] = useState(false)
   <div onm ouseOver={() => {
             setHover(true)
         } 
         onm ouseOut={() => {
             setHover(false)
         }
    >
      {hover ? <Icon onClick={() => { }} className={"callDisconnect"} /> : 
                  <Icon  onClick={() => { }} className={"callConnect"} />} //not updating on hover
    </div>

CodePudding user response:

The only way to cause a rerender in react is to set state. So instead of using a ref, use a state variable:

const App = () => {
  const [hover, setHover] = React.useState(false);

  return (
    <div
      style={{ width: 50, height: 50 }}
      onm ouseOver={() => {
        setHover(true);
      }}
      onm ouseOut={() => {
        setHover(false);
      }}
    >
      {hover ? (
        <div style={{ width: 50, height: 50 }} onClick={() => {}} className={"callDisconnect"} />
      ) : (
        <div style={{ width: 50, height: 50 }} onClick={() => {}} className={"callConnect"} />
      )}
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
.callConnect {
  background-color: green
}
.callDisconnect {
  background-color: red
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

CodePudding user response:

You need to use the useState hook instead of useRef to make your component re-render. Also you can apply the condition directly in the className instead of repeating the whole component just for a class change:

const [hover, setHover] = useState(false);

<div
  onm ouseOver={() => setHover(true)}
  onm ouseOut={() => setHover(false)}
>
    <Icon onClick={() => {}} className={hover ? "callDisconnect" : "callConnect"} />
</div>;
  • Related