CarsonMatz / ButtonExperimenting

Code for responsive button component.
0 stars 0 forks source link

State management and is hovering #1

Open l-monninger opened 2 years ago

l-monninger commented 2 years ago

React functional components are able to persist state within a lifecycle by use of closures and context stores. This article should help you get a sense of how that works.

While your instinct to try and move the function declaration outside of the functional component is a good one, we do in fact need closures to maintain state. So, this cannot be done.

What you could do instead is define a factory:

import { hover } from '@testing-library/user-event/dist/hover';
import React, {FC, useState, ReactElement} from 'react';

export const BUTTON_CLASSNAMES : string = 
    "";

// factories
export const mkHandleMouseEnter = (setHovered : (isHovered : boolean)=>void) : void => () => {
    setHovered(true);
};
export const mkHandleMouseLeave = (setHovered : (isHovered : boolean)=>void) => () => {
    setHovered(false);
};

// ...

export type ButtonProps = {
    style ? : React.CSSProperties;
    //onMouseOver ? : () => {changeBackground()};
    onMouseOver ? : () => void; //doesn't work
    onClick: () => void; //takes in-line function
    variant?: string; // default, submit, continue, info, exit ...
    size?: string; // sm, md, lg ...

    //another unsuccesful attempt at hover
    hover ? : {
        opacity: '0.3'
    };
};

//expirementing more with hover
/* export const onMouseOverHandler = (
    event: React.MouseEvent<HTMLButtonElement>
) => {
    const Button: HTMLButtonElement = event.currentTarget;
    BUTTON_STYLE.opacity = '0.3';
}; */

/* export function changeBackground() {
    BUTTON_STYLE.opacity = '0.3';
}; */

export const Button : FC<ButtonProps>  = ({
    style,
    onMouseOver,
    onClick,
    variant = 'default',
    size = 'md',
}) =>{

   const [isHovered, setHovered] = useState(false);

   // use your factory
   const handleMouseEnter = mkMouseEnter(setHovered);
   const handleMouseLeave = mkMouseLeave(setHovered);

    return (
        <div
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        className={BUTTON_CLASSNAMES}
        onClick={onClick}
        style={{
            ...BUTTON_STYLE, 
            ...style,
            ...hovered ? hoverStyle : {}
         }}>
            Testing
        </div>
    )
};

This is a great pattern to get familiar with. Though in use cases as simple as this may be overkill.

There are further two additional questions you should be asking yourself:

  1. What are the performance tradeoffs of using React state management to implement hover effects? Does it render the visuals faster or slower? Does it use more or less memory in the browser?
  2. How would I allow someone to customize hover behavior? (Hint: this may involve using your factory pattern to wrap props.)
l-monninger commented 2 years ago

@CarsonMatz

l-monninger commented 2 years ago

https://reactjs.org/docs/react-component.html

l-monninger commented 2 years ago

https://reactjs.org/docs/hooks-reference.html#usememo

CarsonMatz commented 2 years ago

The hover aspect works and I get all the code to make it do so. I did't update it further to allow the user to customize the behavior but I think I have a good idea of how to do so. I would just create a factory of options like the change of opacity and map them to an input in App.jsx, right?

l-monninger commented 2 years ago

@CarsonMatz Provide an example of what you're thinking of.