React4.0
render-props和高阶组件
render-props
两个组件中的部分功能相似或相同,可以复用相似的功能(联想函数封装),
复用什么?1.state,2.操作state的方法(组件状态逻辑)
两种方式:1.render props模式;2.高阶组件(HOC)
这两种方式不是API,而是利用React自身特点的编码技巧,演化而成的固定模式(写法)
获取到该组件中复用的state:在使用组件时,添加一个值为函数的prop,通过函数参数来获取(需要组件内部实现)
//render属性的值是一个函数,参数prop是复用的state
<Mouse render={(props)=>{}}
渲染任意的UI:使用该函数的返回值作为要渲染的UI内容(需要组件内部实现)
<Mouse render={(props)=>{
<p>复用的state:{props.name}</p>
}}
步骤:
1.创建要复用的组件(Mouse),在组件中提供复用的状态逻辑代码(1.状态,2.操作状态的方法)
2.将要复用的状态(state)作为props.render(state)方法的参数,暴露到组件外部
3.使用props.render()的返回值作为要渲染的内容
Mouse组件负责:封装复用的状态逻辑代码(1.状态,2.操作状态的方法)
状态:state={x:0,y:0}
操作状态的方法:handle
传入的render prop负责:使用复用的状态来渲染UI结构
import React from 'react';
import ReactDOM from 'react-dom';
import img from "./img/success.png"
// 复用状态,复用函数
class Mouse extends React.Component {
// 状态
state = {
x: 0,
y: 0
}
// 监听鼠标移动
componentDidMount() {
window.addEventListener("mousemove", this.handle)
}
// 监听的事件
handle = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render() {
return (
this.props.render(this.state)
)
}
}
// 使用同一个组件,不同之处在return的内容不同
// mouse就是一个对象,就是Mouse组件的状态state
class App extends React.Component {
render() {
return (
<div>
<p>render props模式</p>
<Mouse render={mouse => {
return (
<p>鼠标的位置:{mouse.x},{mouse.y}</p>
)
}} />
{/* img标签要加alt属性,否则报错 */}
<Mouse render={(mouse) => {
return (
<img src={img} style={{ position: 'absolute', top: mouse.y, left: mouse.x }} alt="pic" />
)
}} />
</div>
)
}
}
ReactDOM.render(
<div><App /></div>,
document.getElementById('root')
);
代码优化
1.推荐:给render props 模式添加props效验
2.应该在组件卸载时解除mousemove事件绑定
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types'
// 导入图片资源
import img from "./img/success.png"
// 复用组件:鼠标位置复用
class Mouse extends React.Component {
// 鼠标位置状态
state = {
x: 0,
y: 0
}
// 监听鼠标移动事件
componentDidMount() {
window.addEventListener("mousemove", this.handle)
}
// 鼠标移动事件的处理
handle = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render() {
return (
// this.props.render(this.state)
//children属性代替render助兴
this.props.children(this.state)
)
}
// 优化推荐:组件卸载时移除监听鼠标移动事件
componentWillUnmount() {
window.removeEventListener("mousemove", this.handle)
}
}
// 优化:添加props效验
// propTypes首字母是小写的,不是导入的PropTypes
Mouse.propTypes = {
// Mouse标签的子节点是一个函数,必要的
children:PropTypes.func.isRequired
}
// 使用同一个组件,不同之处在return的内容不同
// mouse就是一个对象,就是Mouse组件的状态state
class App extends React.Component {
render() {
return (
<div>
<p>render props模式</p>
{/* <Mouse render={mouse => {
return (
<p>鼠标的位置:{mouse.x},{mouse.y}</p>
)
}} /> */}
{/* img标签要加alt属性,否则报错 */}
{/* <Mouse render={(mouse) => {
return (
<img src={img} style={{ position: 'absolute', top: mouse.y, left: mouse.x }} alt="pic" />
)
}} /> */}
<Mouse>
{mouse => {
return (
<p>鼠标的位置:{mouse.x},{mouse.y}</p>
)
}}
</Mouse>
<Mouse>
{mouse => {
return (
<img src={img} style={{ position: "absolute", top: mouse.y, left: mouse.x }} alt='pic' />
)
}}
</Mouse>
</div>
)
}
}
ReactDOM.render(
<div><App /></div>,
document.getElementById('root')
);
高阶组件
目的:实现状态逻辑复用,采用包装(装饰)模式
高阶组件就相当于手机壳,通过包装组件,增强组件功能
**高阶组件(HOC,Higher-Order Component)**是一个函数,接收要包装的组件,返回增强后的组件
高阶组件创建一个类组件,在这个类组件中提供复用的状态逻辑代码,通过prop将复用的状态传递给被包装组件
…:用于解构
import React from 'react';
import ReactDOM from 'react-dom';
// import PropTypes from 'prop-types'
// 导入图片资源
import img from "./img/success.png"
// 1.高阶组件:是一个函数,函数名用with开头
// 参数是一个组件
function withMouse(Wrapped) {
// 创建组件(复用)
class Mouse extends React.Component {
// 状态
state = {
x: 0,
y: 0
}
// 挂载阶段
componentDidMount() {
// 鼠标移动了,就触发this.handle
window.addEventListener("mousemove", this.handle)
}
// 渲染
// 返回的是高阶组件函数的参数,参数就是一个组件
render() {
return (
// ...this.state:解构this.state
<Wrapped {...this.state} />
)
}
// 处理函数
handle = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
// 卸载阶段
componentWillUnmount() {
window.removeEventListener("mousemove", this.handle)
}
}
// 返回组件
return Mouse
}
// 2.需要增强的组件
const Posi = props => {
return (
<p>x:{props.x},y:{props.y}</p>
)
}
// 需要增强的组件
const Icon = props => {
return (
<img src={img} style={{ position: 'absolute', top: props.y, left:props.x }} alt='icon' />
)
}
// 通过增强后的组件
const MousePosi = withMouse(Posi)
const MouseIcon = withMouse(Icon)
class App extends React.Component {
render() {
return (
<div>
{/* 这里显示的都是通过高阶组件增强后的组件 */}
<MousePosi />
<MouseIcon />
</div>
)
}
}
ReactDOM.render(
<div><App /></div>,
document.getElementById('root')
);