render-props和高阶组件
render-props和高阶组件
以上两种方式都是实现状态组件复用
1.1 render props是一种模式
使用render创建复用组件
首先我们创建一个组件,这个组件里面有可以复用的方法和逻辑,下面我们写一个可以获取当前移动坐标的组件(mouse)
import React, { Component } from 'react'
export default class home extends Component {
constructor(props) {
super(props)
this.state = {
x: 0,
y: 0
}
}
handleMouseMove = e => {
console.log(e);
this.setState({
x: e.clientX,
y: e.clientY
})
}
render() {
return this.props.render(this.state) //将要复用的状态作为props.render(state)方法的参数,暴露到外部
}
componentDidMount() { //在组件挂载完成进行鼠标移动事件监听 执行handleMouseMove方法
window.addEventListener('mousemove', this.handleMouseMove)
}
}
然后在需要该逻辑的组件中使用该组件
import React, { Component } from 'react'
import Home from './home'
export default class asign extends Component {
render() {
return (
<div>
//传入参数mouse相当于上面暴露的this.state,在上面中组件暴露什么,那么这里接到的mouse就是什么
//另外这里要注意这里一定要有返回值 因为返回的是数据状态 那么就要渲染HTML,或者null,不然就会报错
<Home render={ mouse=>{ return <p>当前得位置{ mouse.x}y轴{ mouse.y}</p>}} />
</div>
)
}
}
1.2 使用children创建复用组件
注意此刻使用的是children
就不是返回render
而是返回 this.props.children
复用组件的render代码
render() {
return this.props.children(this.state) //将要复用的状态作为props.render(state)方法的参数,暴露到外部
}
父组件使用复用组件的代码
<Home>
{ mouse => {
return (
<p>{ mouse}</p>
)
}
}
</Home>
使用render props模式注意要添加props校验
Mouse.propTypes={
children:PropTypes.func.isRequired
}
如果在使用复用组件没有传递参数就会报错 因为我写的校验规则是children的属性是必填项
最后在做完所有操作之后 要特别注意一点,在react
中所有使用window的方法,比如计时器,上面代码提到的鼠标监听事件,这些都是手动添加的,所以我们在组件销毁的时候一定要解绑事件,做到代码优化
componentWillUnmount(){
window.removeEventListener('mousemove',this.handleMouseMove)
}
高阶组件
其实就是一个函数组件,接收要包装的组件,返回增强后的组件
1.1 首先第一步创建一个函数,名称约定以
with
开头的js
通俗来说高阶函数就好比手机套import React, { Component } from ‘react’
export default function withTest(WrappedComponent) { //创建一个高阶函数以with开头,参数也必须是大写字母开头,因为我们的参数后面是当参数组件渲染的也就是,组件名由参数决定
class test extends Component { //创建一个类组件这里面写逻辑与状态,此组件相当于手机套的核心state = {
x: 0,
y: 0
}
hanldMouseMove = e => {
this.setState({
x:e.clientX,
y:e.clientY
})
}
//控制鼠标状态的逻辑
componentDidMount() {
window.addEventListener('mousemove', this.hanldMouseMove)
}
//自己创建的事件手动销毁
componentWillUnmount(){
window.removeEventListener('mousemove', this.hanldMouseMove)
}
render() {
//返回一个组件,这个组件就是传进来的参数是什么名字就是什么组件,比如我在外部传入test那么最终生成的组件名就是test,相当于<test {...this.state} />
//...this.state,就是传入状态
return <WrappedComponent { ...this.state}></WrappedComponent>
}
}
return test //最终将这个方法返回
}第二步 引入js并传入参数
import React, { Component } from ‘react’
import withTest from ‘./test’ //1.引入高阶函数
import PropTypes from ‘prop-types’
const Position=props=>{return ( //3.定义position的基本属性也就是传入参数的基本属性,props就是高阶函数传入的参数,在这里我们是解构state
横坐标{ props.x}
纵坐标{ props.y}
)}
const TestPosition = withTest(Position)//2.传入参数(Position),并且定义组件名(TestPosition )
export default class asign extends Component {
render() {return (
<div className="home">
<TestPosition></TestPosition> //4.使用组件
</div>
)
}
}
注意这样创建组件就有一个问题,那就是组件名相同,也就是手机壳的名字相同
为了区别组件那么就设置displayName
便于区别调试时不同的组件,在react他的每个组件的命名都是通过displayName
来命名的
1.首先在高阶函数中添加一个名字方法
//修改名字的方法
function getDisplayName(WrappedComponent){
console.log(WrappedComponent);
return WrappedComponent.displayName ||WrappedComponent.name||’Component’
}
打印出WrappedComponent
是这个结果,使用json转换也没用,我就不过多研究,有这方面的了解可以在评论中说出来,指正,我的理解是displayName
是react的组件内置的属性,包括name
跟Component
然后在组件的返回值之前调用就行
test.displayName=
WithTest${ getDisplayName(WrappedComponent)}
完整代码
- 最终生成的组件名
3.高阶组件不能继续向下传递props,所以需要在高阶组件中把props一起传递给组件
在不传递props会发现在组件中是无法获取到的
但是高阶函数那边可以打印 ,说明高阶函数那边接收到了但是没有往下传,解决办法只需要将props
往下传就行
这里就获取到了
还没有评论,来说两句吧...