解决问题:将行为封装,供多个组件使用(在多个组件之间分享某段代码)
组件中的props属性中包含一个"render"属性(该属性为一个返回值为元素的方法),然后在该组件的render方法中
调用该方法,就可以将渲染内容变为动态的。
class Cat extends React.Component { render() { const mouse = this.props.mouse; return ( <img src="./logo" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} /> ); } } class Mouse extends React.Component { constructor(props) { super(props); this.handleMouseMove = this.handleMouseMove.bind(this); this.state = { x: 0, y: 0 }; } handleMouseMove(event) { this.setState({ x: event.clientX, y: event.clientY }); } render() { return ( <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}> {this.props.paint(this.state)} //以下方法就是props.render方法,mouse===this.state // render={mouse => ( // <Cat mouse={mouse} /> // )} </div> ); } } class MouseTracker extends React.Component { render() { return ( <div> <h1>Move the mouse around!</h1> <Mouse paint={mouse => ( <Cat mouse={mouse} /> )}/> </div> ); } }
注意事项:
一、如果使用该方法,那么在组件的props中不要使用"render"来定义,通常,我会使用paint
二、当该动态渲染的组件集成PureComponent的时候,需要将该属性定义为一个实例方法
原因:因为使用React.PureComponent的时候,React会默认使用浅比较,如下代码
if (this._compositeType === CompositeTypes.PureClass) { shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState); }
shallowEqual
会比较 Object.keys(state | props)
的长度是否一致,每一个 key
是否两者都有,并且是否是一个引用,也就是只比较了第一层的值,确实很浅,所以深层的嵌套数据是对比不出来的,正因为这样,如果在render中定义一个"render"方法属性,由于是方法,所以每一次调用reder都会重新定义的该属性,无法通过浅比较,每次都会返回false,会造成不必要的刷新。
解决办法如下:
class MouseTracker extends React.Component { constructor(props) { super(props); // This binding ensures that `this.renderTheCat` always refers // to the *same* function when we use it in render. this.renderTheCat = this.renderTheCat.bind(this); } renderTheCat(mouse) { return <Cat mouse={mouse} />; } render() { return ( <div> <h1>Move the mouse around!</h1> <Mouse render={this.renderTheCat} /> </div> ); } }
由于组件实例化之后,其内部方法也变为实例方法,每次调用的render后”render“属性调用的方法就是该实例方法,每次都是引用同一个位置,所以并不会使
React.PureComponent的优势消失。
参考:https://reactjs.org/docs/render-props.html