diff --git a/src/components/Cube/Cube.jsx b/src/components/Cube/Cube.jsx index a7c323b0f78e..b2481cb91420 100644 --- a/src/components/Cube/Cube.jsx +++ b/src/components/Cube/Cube.jsx @@ -1,92 +1,43 @@ // Import External Dependencies import PropTypes from "prop-types"; -import { Component } from "react"; - -export default class Cube extends Component { - static propTypes = { - hover: PropTypes.bool, - theme: PropTypes.string, - depth: PropTypes.number, - repeatDelay: PropTypes.number, - className: PropTypes.string, - continuous: PropTypes.bool, - }; - - static defaultProps = { - hover: false, - theme: "dark", - depth: 30, - repeatDelay: 1000, - }; +import { useEffect, useRef, useState } from "react"; - state = { - x: 0, - y: 0, - z: 0, - iteration: 0, - }; +export default function Cube({ + hover = false, + theme = "dark", + depth = 30, + repeatDelay = 1000, + className = "", + continuous, +}) { + const [state, setState] = useState({ x: 0, y: 0, z: 0, iteration: 0 }); + const containerRef = useRef(null); + const timeoutRef = useRef(null); - render() { - const { x, y, z } = this.state; - const { theme, depth, className = "" } = this.props; + const { x, y, z, iteration } = state; - return ( -
- (this.container = ref)} - className={`cube cube--${theme} relative block [transform-style:preserve-3d]`} - style={{ - width: `${depth}px`, - paddingBottom: `${depth * 0.5}px`, - transform: "rotateX(-35.5deg) rotateY(45deg)", - }} - > -
- {this._getFaces("outer")} -
-
- {this._getFaces("inner")} -
-
-
- ); - } - - componentDidMount() { - const { hover, continuous, repeatDelay } = this.props; + useEffect(() => { + const container = containerRef.current; if (hover) { - this.container.addEventListener("mouseenter", this._spin); - this.container.addEventListener("mouseleave", this._reset); + const spin = () => { + const axes = ["x", "y", "z", "iteration"]; + const axis = axes[Math.floor(Math.random() * axes.length)]; + const sign = Math.random() < 0.5 ? -1 : 1; + setState((prev) => ({ ...prev, [axis]: sign * 90 })); + }; + + const reset = () => { + setState((prev) => ({ ...prev, x: 0, y: 0, z: 0 })); + }; + + container.addEventListener("mouseenter", spin); + container.addEventListener("mouseleave", reset); + + return () => { + container.removeEventListener("mouseenter", spin); + container.removeEventListener("mouseleave", reset); + }; } else if (continuous) { let degrees = 0; const axis = "y"; @@ -94,10 +45,11 @@ export default class Cube extends Component { const animation = () => { const obj = {}; obj[axis] = degrees += 90; - this.setState({ + setState((prev) => ({ + ...prev, ...obj, - iteration: (this.state.iteration + 1) % 4, - }); + iteration: (prev.iteration + 1) % 4, + })); // eslint-disable-next-line no-use-before-define tick(); }; @@ -105,30 +57,13 @@ export default class Cube extends Component { const tick = () => setTimeout(() => requestAnimationFrame(animation), repeatDelay); - this._timeout = tick(); - } - } - - componentWillUnmount() { - const { hover, continuous } = this.props; + timeoutRef.current = tick(); - if (hover) { - this.container.removeEventListener("mouseenter", this._spin); - this.container.removeEventListener("mouseleave", this._reset); - } else if (continuous) { - clearTimeout(this._timeout); + return () => clearTimeout(timeoutRef.current); } - } - - /** - * Get all faces for a cube - * - * @param {'inner' | 'outer' } type - * @return {array} - An array of nodes - */ - _getFaces(type) { - const { iteration } = this.state; + }, []); // eslint-disable-line react-hooks/exhaustive-deps + const getFaces = (type) => { // Keep the thicker border on // the outside on each iteration const borderWidthMap = { @@ -201,50 +136,70 @@ export default class Cube extends Component { key={i} className={`cube__face ${baseFaceClasses} ${variantClasses}`} style={{ - transform: `${rotation} translateZ(${this.props.depth / 2}px)`, + transform: `${rotation} translateZ(${depth / 2}px)`, ...borderStyles, }} /> ); }); - } - - /** - * Get a random axis - * - * @return {string} - A random axis (i.e. x, y, or z) - */ - _getRandomAxis() { - const axes = Object.keys(this.state); - - return axes[Math.floor(Math.random() * axes.length)]; - } - - /** - * Spin the cubes in opposite directions semi-randomly - * - * @param {object} e - Native event - */ - _spin = () => { - const obj = {}; - const axis = this._getRandomAxis(); - const sign = Math.random() < 0.5 ? -1 : 1; - - obj[axis] = sign * 90; - - this.setState(obj); }; - /** - * Rotate the cubes back to their original position - * - * @param {object} e - Native event - */ - _reset = () => { - this.setState({ - x: 0, - y: 0, - z: 0, - }); - }; + return ( +
+ +
+ {getFaces("outer")} +
+
+ {getFaces("inner")} +
+
+
+ ); } + +Cube.propTypes = { + hover: PropTypes.bool, + theme: PropTypes.string, + depth: PropTypes.number, + repeatDelay: PropTypes.number, + className: PropTypes.string, + continuous: PropTypes.bool, +};