From 7d4936293cd6cf3e71c1c50135ddc4fb30f414b2 Mon Sep 17 00:00:00 2001
From: joshwooding <12938082+joshwooding@users.noreply.github.com>
Date: Sun, 14 Apr 2019 03:53:38 +0100
Subject: [PATCH 1/9] [Slide] Convert to function component
---
packages/material-ui/src/Slide/Slide.js | 225 ++++++-------
packages/material-ui/src/Slide/Slide.test.js | 327 ++++++++++++-------
2 files changed, 313 insertions(+), 239 deletions(-)
diff --git a/packages/material-ui/src/Slide/Slide.js b/packages/material-ui/src/Slide/Slide.js
index 8dd707350e3cd1..2f5f6fb4a1d9e5 100644
--- a/packages/material-ui/src/Slide/Slide.js
+++ b/packages/material-ui/src/Slide/Slide.js
@@ -3,11 +3,10 @@
import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
-import EventListener from 'react-event-listener';
import debounce from 'debounce'; // < 1kb payload overhead when lodash/debounce is > 3kb.
import Transition from 'react-transition-group/Transition';
import ownerWindow from '../utils/ownerWindow';
-import { setRef } from '../utils/reactHelpers';
+import { useForkRef } from '../utils/reactHelpers';
import withTheme from '../styles/withTheme';
import { duration } from '../styles/transitions';
import { reflow, getTransitionProps } from '../transitions/utils';
@@ -73,63 +72,43 @@ export function setTranslateValue(props, node) {
* The Slide transition is used by the [Drawer](/demos/drawers/) component.
* It uses [react-transition-group](https://github.com/reactjs/react-transition-group) internally.
*/
-class Slide extends React.Component {
- mounted = false;
-
- constructor() {
- super();
-
- if (typeof window !== 'undefined') {
- this.handleResize = debounce(() => {
- // Skip configuration where the position is screen size invariant.
- if (this.props.in || this.props.direction === 'down' || this.props.direction === 'right') {
- return;
- }
-
- if (this.childDOMNode) {
- setTranslateValue(this.props, this.childDOMNode);
- }
- }, 166); // Corresponds to 10 frames at 60 Hz.
- }
- }
-
- componentDidMount() {
- this.mounted = true;
-
- // state.mounted handle SSR, once the component is mounted, we need
- // to properly hide it.
- if (!this.props.in) {
- // We need to set initial translate values of transition element
- // otherwise component will be shown when in=false.
- this.updatePosition();
- }
- }
-
- componentDidUpdate(prevProps) {
- if (prevProps.direction !== this.props.direction && !this.props.in) {
- // We need to update the position of the drawer when the direction change and
- // when it's hidden.
- this.updatePosition();
- }
- }
-
- componentWillUnmount() {
- this.handleResize.clear();
- }
+function Slide(props) {
+ const {
+ children,
+ direction,
+ in: inProp,
+ onEnter,
+ onEntering,
+ onExit,
+ onExited,
+ style,
+ theme,
+ ...other
+ } = props;
+
+ const mountedRef = React.useRef(false);
+ const childrenRef = React.useRef();
+ const [prevDirection, setPrevDirection] = React.useState();
+ /**
+ * used in cloneElement(children, { ref: handleRef })
+ */
+ const handleOwnRef = ref => {
+ // #StrictMode ready
+ childrenRef.current = ReactDOM.findDOMNode(ref);
+ };
+ const handleRef = useForkRef(children.ref, handleOwnRef);
- handleEnter = node => {
- setTranslateValue(this.props, node);
+ const handleEnter = node => {
+ setTranslateValue(props, node);
reflow(node);
- if (this.props.onEnter) {
- this.props.onEnter(node);
+ if (onEnter) {
+ onEnter(node);
}
};
- handleEntering = node => {
- const { theme } = this.props;
-
- const transitionProps = getTransitionProps(this.props, {
+ const handleEntering = node => {
+ const transitionProps = getTransitionProps(props, {
mode: 'enter',
});
node.style.webkitTransition = theme.transitions.create('-webkit-transform', {
@@ -142,15 +121,13 @@ class Slide extends React.Component {
});
node.style.webkitTransform = 'translate(0, 0)';
node.style.transform = 'translate(0, 0)';
- if (this.props.onEntering) {
- this.props.onEntering(node);
+ if (onEntering) {
+ onEntering(node);
}
};
- handleExit = node => {
- const { theme } = this.props;
-
- const transitionProps = getTransitionProps(this.props, {
+ const handleExit = node => {
+ const transitionProps = getTransitionProps(props, {
mode: 'exit',
});
node.style.webkitTransition = theme.transitions.create('-webkit-transform', {
@@ -161,78 +138,92 @@ class Slide extends React.Component {
...transitionProps,
easing: theme.transitions.easing.sharp,
});
- setTranslateValue(this.props, node);
+ setTranslateValue(props, node);
- if (this.props.onExit) {
- this.props.onExit(node);
+ if (onExit) {
+ onExit(node);
}
};
- handleExited = node => {
+ const handleExited = node => {
// No need for transitions when the component is hidden
node.style.webkitTransition = '';
node.style.transition = '';
- if (this.props.onExited) {
- this.props.onExited(node);
+ if (onExited) {
+ onExited(node);
}
};
- /**
- * used in cloneElement(children, { ref: handleRef })
- */
- handleRef = ref => {
- // #StrictMode ready
- this.childDOMNode = ReactDOM.findDOMNode(ref);
- setRef(this.props.children.ref, ref);
- };
+ const updatePosition = React.useCallback(() => {
+ if (childrenRef.current) {
+ setTranslateValue(props, childrenRef.current);
+ }
+ }, [props]);
+
+ React.useEffect(() => {
+ const handleResize = debounce(() => {
+ // Skip configuration where the position is screen size invariant.
+ if (inProp || direction === 'down' || direction === 'right') {
+ return;
+ }
+
+ if (childrenRef.current) {
+ setTranslateValue(props, childrenRef.current);
+ }
+ }, 166); // Corresponds to 10 frames at 60 Hz.
+
+ window.addEventListener('resize', handleResize);
- updatePosition() {
- if (this.childDOMNode) {
- setTranslateValue(this.props, this.childDOMNode);
+ return () => {
+ handleResize.clear();
+ window.removeEventListener('resize', handleResize);
+ };
+ }, [direction, inProp, props]);
+
+ React.useEffect(() => {
+ // state.mounted handle SSR, once the component is mounted, we need
+ // to properly hide it.
+ if (!inProp && !mountedRef.current) {
+ // We need to set initial translate values of transition element
+ // otherwise component will be shown when in=false.
+ updatePosition();
}
- }
+ mountedRef.current = true;
+ }, [inProp, updatePosition]);
- render() {
- const {
- children,
- direction,
- in: inProp,
- onEnter,
- onEntering,
- onExit,
- onExited,
- style,
- theme,
- ...other
- } = this.props;
-
- return (
-