Open SUNYIMIN opened 4 years ago
现在有这么一个需求,组件A和组件B同时需要展示鼠标的光标在浏览器中的位置
常规的做法:
export default class A extends React.Component {
constructor(props) {
super(props)
this.state = {
x: 0,
y: 0
};
this.handleMouseMove = this.handleMouseMove.bind(this);
}
componentDidMount() {
document.addEventListener('mousemove', this.handleMouseMove, false);
}
componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove, false);
}
handleMouseMove(e) {
this.setState({
x: e.clientX,
y: e.clientY
});
}
render() {
const {x, y} = this.state;
<>
<div>A: ({x}, {y})</div>
</>
}
}
export default class B extends React.Component {
constructor(props) {
super(props)
this.state = {
x: 0,
y: 0
};
this.handleMouseMove = this.handleMouseMove.bind(this);
}
componentDidMount() {
document.addEventListener('mousemove', this.handleMouseMove, false);
}
componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove, false);
}
handleMouseMove(e) {
this.setState({
x: e.clientX,
y: e.clientY
});
}
render() {
const {x, y} = this.state;
<>
<div>B: ({x}, {y})</div>
</>
}
}
很明显可以看出组件A和组件B之前在获取光标位置的这段逻辑是重复的。我们可以尝试上面三种方式,将这段逻辑抽离出来
hoc的方式:
export default function(title) {
return function (WrappedComponent) {
return class HOC extends Component {
constructor(props) {
super(props)
this.state = {
x: 0,
y: 0
};
this.handleMouseMove = this.handleMouseMove.bind(this);
}
componentDidMount() {
console.log(111)
document.addEventListener('mousemove', this.handleMouseMove, false);
}
componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove, false);
}
handleMouseMove(e) {
this.setState({
x: e.clientX,
y: e.clientY
});
}
render() {
const {x, y} = this.state;
return (
<div>
<div>{title}</div>
<WrappedComponent x={x} y={y}/>
</div>
)
}
}
}
}
renderProps的方式
import React from 'react'
export default class Provide extends React.Component {
constructor(props) {
super(props)
this.state = {
x: 0,
y: 0
};
this.handleMouseMove = this.handleMouseMove.bind(this);
}
componentDidMount() {
document.addEventListener('mousemove', this.handleMouseMove, false);
}
componentWillUnmount() {
document.removeEventListener('mousemove', this.handleMouseMove, false);
}
handleMouseMove(e) {
this.setState({
x: e.clientX,
y: e.clientY
});
}
render() {
const {x, y} = this.state;
return this.props.render(x, y)
}
}
hooks的方式
const useXy = (props) => {
//useState可以传入函数,延迟初始值的渲染
const [position, setPosition] = useState(() => {
return {
x: 0,
y: 0
}
})
function handleMouseMove(e) {
setPosition({
x: e.clientX,
y: e.clientY,
});
}
useEffect((e) => {
// 注册事件
console.log(11)
document.addEventListener('mousemove', handleMouseMove, false);
// 销毁事件
return () => {
document.removeEventListener('mousemove', handleMouseMove, false);
};
}, [position]);
//当position改变的时候useEffect才会执行,空数组的话useEffect只执行一次
return position;
}
export default useXy
总结三者的优缺点:
react中如果组件之间有一些相同的逻辑,我可以通过hoc,renderProps,hooks这三种方式将组件间的通用逻辑抽离出来,方便组件间逻辑的复用。 那如果这三种方式都能实现,那么它们之间有什么区别?