@[toc]
高阶组件
什么是高阶组件
高阶组件就是一个 React 组件包裹着另外一个 React 组件
其中“包裹”的概念,因为它可能会有以下两种不同的含义之一:
- Props Proxy: HOC 对传给
WrappedComponent
的porps
进行操作, - Inheritance Inversion: HOC 继承
WrappedComponent
。
Props Proxy
//Props Proxy 最简实现
function ppHOC(WrappedComponent) {
return class PP extends React.Component {
render() {
return <WrappedComponent {...this.props} />
}
}
}
使用 Props Proxy 可以做什么
• 操作 props
• 通过 Refs 访问到组件实例
• 提取 state
• 用其他元素包裹WrappedComponent
1.操作 props
function ppHOC(WrappedComponent) {
return class PP extends React.Component {
render() {
const newProps = {
id: newId
}
return <WrappedComponent {...this.props} {...newProps} />
}
}
}
2.通过 Refs 访问到组件实例
function refsHOC(WrappedComponent) {
return class RefsHOC extends React.Component {
proc(wrappedComponentInstance) {
wrappedComponentInstance.method()
}
render() {
const props = Object.assign({}, this.props, { ref: this.proc.bind(this) })
return <WrappedComponent {...props} />
}
}
}
const refHoc = WrappedComponent => class extends Component {
componentDidMount() {
console.log(this.instanceComponent, 'instanceComponent');
}
render() {
return (<WrappedComponent
{...this.props}
ref={instanceComponent => this.instanceComponent = instanceComponent}
/>);
}
};
3.提取 state
function ppHOC(WrappedComponent) {
return class PP extends React.Component {
constructor(props) {
super(props)
this.state = {
name: ''
}
this.onNameChange = this.onNameChange.bind(this)
}
onNameChange(event) {
this.setState({
name: event.target.value
})
}
render() {
const newProps = {
name: {
value: this.state.name,
onChange: this.onNameChange
}
}
return <WrappedComponent {...this.props} {...newProps} />
}
}
}
@ppHOC
class Example extends React.Component {
render() {
return <input name="name" {...this.props.name} />
}
}
4.包裹WrappedComponent
function ppHOC(WrappedComponent) {
return class PP extends React.Component {
render() {
return (
<div style={{ display: 'block' }}>
<WrappedComponent {...this.props} />
</div>
)
}
}
}
Inheritance Inversion
Inheritance Inversion 最简实现
function iiHOC(WrappedComponent) {
return class Enhancer extends WrappedComponent {
render() {
return super.render()
}
}
}
调用顺序
didmount→HOC didmount→will unmount→HOC will unmount
使用 Inheritance Inversion可以做什么
• 渲染劫持
• 操作 state
1.渲染挟持
• 有条件地渲染元素树
const MyContainer = (WrappedComponent) => class extends WrappedComponent {
render() {
if (this.props.loggedIn) {
return super.render();
} else {
return null;
}
}
}
• 读取和修改由 render 输出的 React 元素树
const MyContainer = (WrappedComponent) => class extends WrappedComponent {
render() {
const elementsTree = super.render();
let newProps = {};
if (elementsTree && elementsTree.type === 'input') {
newProps = { value: 'may the force be with you' };
}
const props = Object.assign({}, elementsTree.props, newProps);
const newElementsTree = React.cloneElement(elementsTree, props, elementsTree.props.children);
return newElementsTree;
}
}
2.操作state
高阶组件可以读取、修改 WrappedComponent 实例中的 state,如果需要的话,也可以 增加 state。但这样做,可能会让 WrappedComponent 组件内部状态变得一团糟。
const MyContainer = (WrappedComponent) => class extends WrappedComponent {
render() {
return (
<p>
<p>Props</p>
<pre>{JSON.stringify(this.props)}</pre>
<p>State</p>
<pre>{JSON.stringify(this.state)}</pre>
{super.render()}
</p>);
}
}
装饰器
高阶组件可以看做是装饰器模式(Decorator Pattern)在React的实现。即允许向一个现有的对象添加新的功能,同时又不改变其结构,属于包装模式(Wrapper Pattern)的一种
ES6中添加了一个decorator的属性,使用@符表示,可以更精简的书写。
function HOCFactoryFactory(...params) {
// do something with params
return function HOCFactory(WrappedComponent) {
return class HOC extends React.Component {
render() {
return <WrappedComponent {...this.props} />
}
}
}
}
HOCFactoryFactory(params)(WrappedComponent)
//或
@HOCFatoryFactory(params)
class WrappedComponent extends React.Component{}
该篇文章借鉴了沈老师的总结笔记,还有许多大佬的博客,如果有涉及侵权的,请联系我删除。