React学习系列(二)

高阶组件

高阶组件其实是一个函数,接收一个组件作为参数,返回一个包装组件作为返回值,类似于高阶函数。

属性代理

操作props

可以对原组件的props进行增删改查,通常是查找和增加,删除和修改的话,需要考虑到不能破坏原组件。

通过refs访问组件实例

可以通过ref回调函数的形式来访问传入组件的实例,进而调用组件相关方法或其他操作。

提取state

通过传入 props 和回调函数把 state 提取出来

包裹WrappedComponent

为了封装样式、布局等目的,可以将WrappedComponent用组件或元素包裹起来。

反向继承

高阶组件继承于被包裹的React组件

1
2
3
4
5
6
7
const MyContainer = (WrappedComponent)=>{
class extends WrappedComponent {
render(){
return super.render();
}
}
}

渲染劫持

渲染劫持就是指的是高阶组件可以控制 WrappedComponent的渲染过程,并渲染各种各样的结果。我们可以在这个过程中在任何React元素输出的结果中读取、增加、修改、删除props,或读取或修改React元素树,或条件显示。又或者用样式包裹元素树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function hoc(ComponentClass) {
return class HOC extends ComponentClass {
render() {
const elementTree = super.render();
elementTree.props.children = elementTree.props.children.filter((z) => {
return z.type !== "ul" && z;
}
const newTree = React.cloneElement(elementTree);
return newTree;
}
}
}

@hoc
export default class ComponentClass extends React.Component {
render() {
const divStyle = {
width: '100px',
height: '100px',
backgroundColor: 'red'
};

return (
<div>
<p style={{color: 'brown'}}>啦啦啦</p>
<ul>
<li>1</li>
<li>2</li>
</ul>
<h1>哈哈哈</h1>
</div>
)
}
}

操作state

HOC可以读取,编辑和删除WrappedComponent实例的state,可以添加state。不过这个可能会破坏WrappedComponent的state,所以,要限制HOC读取或添加state,添加的state应该放在单独的命名空间里,而不是和WrappedComponent的state混在一起。

条件渲染

当 this.props.loggedIn 为 true 时,这个 HOC 会完全渲染 WrappedComponent 的渲染结果。(假设 HOC 接收到了 loggedIn 这个 prop)

1
2
3
4
5
6
7
8
9
10
11
function iHOC(WrappedComponent) {
return class Enhancer extends WrappedComponent {
render() {
if (this.props.loggedIn) {
return super.render()
} else {
return null
}
}
}
}

解决WrappedComponent名字丢失问题

用HOC包裹的组件会丢失原先的名字,影响开发和调试。可以通过在WrappedComponent的名字上加一些前缀来作为HOC的名字,以方便调试。

1
2
3
4
5
6
7
8
9
10
11
class HOC extends ... {
static displayName = `HOC(${getDisplayName(WrappedComponent)})`
//
}

// getDisplayName
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'
}