Alexander Hemming
Alexander Hemming

Reputation: 801

Is it bad to use Refs to change styles in react?

here is a code example where i use Ref's to change style

import React, {useRef, useState, useEffect} from 'react'
import S from "./collapsible.module.css"

import PropTypes from 'prop-types'
import { faMinus, faPlus } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'

function Collapsible(props) {
let myRef = useRef(null);
let buttonRef = useRef(null);
let [ button, setButton] = useState(true)


let Show = () => {
    if(button) {
setButton(false)
buttonRef.current.style.backgroundColor = "#555"
myRef.current.style.maxHeight = myRef.current.scrollHeight + "px";
} else {

setButton(true)
buttonRef.current.style.backgroundColor = "hsl(181, 100%, 11%)"
myRef.current.style.maxHeight =  "0px";
}
}


    return (
        <div
        className={S.body}
        >
            <button 
            className={S.collapsible}
onClick={Show}
ref={buttonRef}
            > {props.label}
            
            <div className={S.icon}> 
    {button? <FontAwesomeIcon icon={faPlus} />:
<FontAwesomeIcon icon={faMinus} />}
</div> 
            </button>
            <div 
            className={S.content}
            ref={myRef}
            >
<h3>{props.body}</h3>
            </div>
        </div>
    )
}
Collapsible.propTypes = {
    label: PropTypes.string,
    body: PropTypes.string,
  }
  
  Collapsible.defaultProps = {
    label: '',
    body: "",
  }
export default Collapsible

css:

.collapsible {
    display: flex;
    background-color: hsl(181, 100%, 11%);
    color: white;
    cursor: pointer;
    padding: 18px;
    width: 100%;
    border: none;
    outline: none;
    font-size: 15px;
    border-radius: 3px;
    /* margin-bottom: 3px; */
    box-shadow: 0px 1px 5px 1px black;
    margin-top:13px;
  }
  .icon{
    color:white;
    position:absolute;
    right:50px;
text-align:right;
justify-content: flex-end;
}
  
  .active, .collapsible:hover {
    background-color: #555;
  }
  
  .content {
    padding: 0 18px;
    max-height: 0px;
    overflow: hidden;
    transition: max-height 0.2s ease-out;
    background-color: #f1f1f1;
  }

This is just replicating this in React: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_collapsible_animate

I have read that using Refs is bad, especially when using it to change the DOM, but if I didn't change the style with the exact amount shown in "scrollHeight" then the transition would be a messed up speed.

If there is another method Is this still bad practice?

Upvotes: 1

Views: 3023

Answers (2)

JurijsReact
JurijsReact

Reputation: 150

  1. Refs is definitely better if you work with fast scrolling of the window Because state works very slow from the listeners: (

Upvotes: 0

Ali Klein
Ali Klein

Reputation: 1908

It's more common practice to use a state value to determine the style like this:

  <button 
     className={S.collapsible} 
     onClick={Show} 
     style={{backgroundColor: button ? "#555" : "hsl(181, 100%, 11%)"}
   >
    {props.label}
    <div className={S.icon}>
      {button ? (
        <FontAwesomeIcon icon={faPlus} />
      ) : (
        <FontAwesomeIcon icon={faMinus} />
      )}
    </div>
  </button>

Or have a conditional className for your styles:

 <button
    className={`${S.collapsible} ${
      button ? S.buttonColor : S.anotherButtonColor
    }`}
    onClick={Show}
  >
    {props.label}
    <div className={S.icon}>
      {button ? (
        <FontAwesomeIcon icon={faPlus} />
      ) : (
        <FontAwesomeIcon icon={faMinus} />
      )}
    </div>
  </button>

and add .buttonColor and .anotherButtonColor to your CSS Module file (collapsible.module.css).

.buttonColor {
    background-color: #555;
}

.anotherButtonColor {
    background-color: hsl(181, 100%, 11%);
}

For the maxHeight on myRef, I'd do something like:

  <div className={S.content} ref={myRef}>
    <div style={{ maxHeight: myRef.current.scrollHeight }}>
      <h3>{props.body}</h3>
    </div>
  </div>

Upvotes: 1

Related Questions