an expandable and shrinking react component. Inside the component, there is a button to switch between shrinking and expanding, and pull down, pull up and expand in the internal support of the component, and throw onChange events when changing
.how to rewrite this component to the format recommended by React16.4
import React from "react";
import styles from "./style.scss";
class ExpandedView extends React.Component {
constructor(props) {
super(props);
this.state = {
expanded: false,
};
//
this.containerNode = null;
this.startX = 0;
this.startY = 0;
this.endX = 0;
this.endY = 0;
this.clickArrow = this.clickArrow.bind(this);
this.onContainerTouchStart = this.onContainerTouchStart.bind(this);
this.onContainerTouchEnd = this.onContainerTouchEnd.bind(this);
}
componentWillReceiveProps(nextProps) {
const { expanded: newExpanded, onChange } = nextProps;
if (this.state.expanded !== newExpanded) {
onChange && onChange(newExpanded);
this.setState({ expanded: newExpanded });
}
}
async componentDidMount() {
let { expanded, onChange } = this.props;
onChange && onChange(expanded);
this.setState({ expanded });
if (this.containerNode) {
this.containerNode.addEventListener("touchstart", this.onContainerTouchStart);
this.containerNode.addEventListener("touchend", this.onContainerTouchEnd);
}
}
componentWillUnmount() {
if (this.containerNode) {
this.containerNode.removeEventListener("touchstart", this.onContainerTouchStart);
this.containerNode.removeEventListener("touchend", this.onContainerTouchEnd);
}
}
onContainerTouchStart(e) {
this.startX = e.touches[0].pageX;
this.startY = e.touches[0].pageY;
}
onContainerTouchEnd(e) {
let { onChange } = this.props;
this.endX = e.changedTouches[0].pageX;
this.endY = e.changedTouches[0].pageY;
const direction = getDirection(this.startX, this.startY, this.endX, this.endY, 30);
//
if (direction === "up") {
this.setState({ expanded: true });
onChange && onChange(true);
//
} else if (direction === "down") {
this.setState({ expanded: false });
onChange && onChange(false);
}
}
//
clickArrow() {
let { onChange } = this.props;
this.setState((prevState) => {
let expanded = !prevState.expanded;
onChange && onChange(expanded);
return { expanded };
});
}
render() {
const { expanded } = this.state;
return (
<div
ref={node => this.containerNode = node}
className={cn(styles.container, { [styles.collapsed]: !expanded })}
>
<div className={styles["arrow-wrapper"]} onClick={() => this.clickArrow()} />
<div className={cn(styles["collapsed-panel"], { [styles.hide]: expanded })}>
<div>collapsed</div>
</div>
<div className={cn(styles["expanded-panel"], { [styles.hide]: !expanded })}>
<div>expanded</div>
</div>
</div>
);
}
}
export default ExpandedView;
I rewrote it as
static getDerivedStateFromProps(nextProps, prevState) {
const { expanded: currentExpanded, onChange } = nextProps;
if (currentExpanded !== prevState.expanded) {
onChange && onChange(currentExpanded);
return {
expanded: currentExpanded,
};
}
return null;
}
After , I found that the setState of clickArrow will also call getDerivedStateFromProps, which makes it impossible to switch between shrink and expand. How should I solve this problem?
should the behavior of a component like this control its own state be performed within the component or just throw an event so that the external component decides the value of expanded by passing props