有时候,某些组建的各种功能及其处理逻辑几乎完全相同,只是显示的界面不一样,建议下面的方式选择其一来解决重复代码的问题(横切关注点)
实现这两个组建,我们通常的写法是:
// MoveBox
class MoveBox extends PureComponent {state = {x: 0,y: 0};myRef = React.createRef();handleMove = e => {// e不是真实的dom对象,是经过包装的,不存在offsetX 或 offsetY// 但是其存在 pageX (距离页面 pageY) or clientX(距离视口 clientY)const { clientX, clientY } = e;const { left, top } = this.myRef.current.getBoundingClientRect();console.log(clientX - left);this.setState({x: clientX - left,y: clientY - top});};render() {return (<div className="moveBox" onMouseMove={this.handleMove} ref={this.myRef}><divclassName="moveDiv"style={{left: `${this.state.x}px`,top: `${this.state.y}px`}}></div></div>);}
}// MoveMessage
class MoveMessage extends PureComponent {state = {x: 0,y: 0};myRef = React.createRef();handleMove = e => {// e不是真实的dom对象,是经过包装的,不存在offsetX 或 offsetY// 但是其存在 pageX (距离页面 pageY) or clientX(距离视口 clientY)const { clientX, clientY } = e;const { left, top } = this.myRef.current.getBoundingClientRect();this.setState({x: clientX - left,y: clientY - top});};render() {return (<div className="moveBox" onMouseMove={this.handleMove} ref={this.myRef}><p>x:{this.state.x},y:{this.state.y}</p></div>);}
}// MoveContainer
class MoveContainer extends PureComponent {render() {return (<div><MoveBox /><MoveMessage /></div>);}
}
会发现存在很多重复的代码
1.模仿context.Consumer
? 1.某个组件,需要某个属性
? 2.该属性是一个函数,函数的返回值用于渲染
? 3.函数的参数会传递为需要的数据
? 4.注意纯组件的属性(尽量避免每次传递的render props的地址不一致)
// MoveContainer
class MoveContainer extends PureComponent {moveBox = value => (<divclassName="moveDiv"style={{left: `${value.x}px`,top: `${value.y}px`}}></div>);moveMessage = value => (<p>x:{value.x},y:{value.y}</p>);render() {return (<div><MoveIndex>{this.moveBox}</MoveIndex><MoveIndex>{this.moveMessage}</MoveIndex></div>);}
}// MoveIndex 将MoveBox 和MoveMessage 合成一个组件,渲染内容用函数替代
class MoveIndex extends PureComponent {state = {x: 0,y: 0};myRef = React.createRef();handleMove = e => {// e不是真实的dom对象,是经过包装的,不存在offsetX 或 offsetY// 但是其存在 pageX (距离页面 pageY) or clientX(距离视口 clientY)const { clientX, clientY } = e;const { left, top } = this.myRef.current.getBoundingClientRect();this.setState({x: clientX - left,y: clientY - top});};render() {return (<div className="moveBox" onMouseMove={this.handleMove} ref={this.myRef}>{this.props.children(this.state)}</div>);}
}
2.render Props
? 1.某个组件,需要某个属性
? 2.该属性是一个函数,函数的返回值用于渲染
? 3.函数的参数会传递为需要的数据
? 4.注意纯组件的属性(尽量避免每次传递的render props的地址不一致)
? 5.通常该属性的名字加做render
写法与1相似,
// MoveContainer
class MoveContainer extends PureComponent {moveBox = value => (<divclassName="moveDiv"style={{left: `${value.x}px`,top: `${value.y}px`}}></div>);moveMessage = value => (<p>x:{value.x},y:{value.y}</p>);render() {return (<div>{/* 这个传入组件函数使用render这个属性 */}<MoveIndex render={this.moveBox} /> <MoveIndex render={this.moveMessage} /></div>);}
}// MoveIndex
class MoveIndex extends PureComponent {state = {x: 0,y: 0};myRef = React.createRef();handleMove = e => {// e不是真实的dom对象,是经过包装的,不存在offsetX 或 offsetY// 但是其存在 pageX (距离页面 pageY) or clientX(距离视口 clientY)const { clientX, clientY } = e;const { left, top } = this.myRef.current.getBoundingClientRect();this.setState({x: clientX - left,y: clientY - top});};render() {return (<div className="moveBox" onMouseMove={this.handleMove} ref={this.myRef}>{/* 组件内部 使用this.props.render接收 */}{this.props.render(this.state)}</div>);}
}
3.HOC
// MoveHoc
function MoveHoc(Comp) {return class MoveIndex extends PureComponent {state = {x: 0,y: 0};myRef = React.createRef();handleMove = e => {// e不是真实的dom对象,是经过包装的,不存在offsetX 或 offsetY// 但是其存在 pageX (距离页面 pageY) or clientX(距离视口 clientY)const { clientX, clientY } = e;const { left, top } = this.myRef.current.getBoundingClientRect();this.setState({x: clientX - left,y: clientY - top});};render() {return (<div className="moveBox" onMouseMove={this.handleMove} ref={this.myRef}><Comp {...this.state} /></div>);}};
}// MoveContainer
function MoveBox(props) {return (<divclassName="moveDiv"style={{left: `${props.x}px`,top: `${props.y}px`}}></div>);
}function MoveMessage(props) {return (<p>x:{props.x},y:{props.y}</p>);
}const HocMoveBox = MoveHoc(MoveBox);
const HocMoveMessage = MoveHoc(MoveMessage);export default class MoveContainer extends PureComponent {render() {return (<div><HocMoveBox /><HocMoveMessage /></div>);}
}