React.js |高阶组件的应用

什么是高阶组件

高阶组件(HOC)是 React 中用于复用组件逻辑的一种技巧,让它重复的逻辑在许多组件中得到共享。简单的说,高阶组件是一个以组件作为参数,并返回新组件的函数。

//其中WrapedComponent是包裹后的组件,wrapedComponent是高阶组件(函数),RawComponent是你想包裹的组件
const WrapedComponent = wrapedComponent(RawComponent);

应用场景1-更改props

//WrapComponent.js(高阶组件)
const wrapComponent = (OriginalComponent) => class extends Component{
    handleClick(){console.log('Well Done!')}
	render(){
        const newProps={
			say:'Click me!',
			handleClick:this.handleClick
		}
        //先是解构原来的,后面解构新加入的
		return(
			<OriginalComponent {...this.props} {...newProps}/>
		)
	}
}
//SayHi.js(原始组件)
//1.引入高阶组件
import wrapComponent from './WrapComponent'
//2.原始组件
function SayHi(props){
    return(
         <div>hello!{props.name}<br/><h1 onClick={props.handleClick}>{props.say}</h1></div>
    )
}
//3.导出包裹后的组件
export default wrapComponent(SayHi)
//App.js
import SayHi from './SayHi'
class App extends Component {
  render(){
    return(
      <SayHi name={'Lisa'}/>
    )
  }
}

image.png

应用场景2-与其他组件一起包裹

//传进来的组件在另一个组件OtherComponent中渲染,最后返回另一个组件OtherComponent
//这意味着可以将一些常用的生命周期放在这里,那么在原来的组件就不必重复写
function wrapComponent(OriginalComponent) {
    class OtherComponent extends React.Component {
      componentDidMount(){
		console.log('常用的')
	  }
      render() {
        return <OriginalComponent {...this.props}/>;
      }
    }
    return OtherComponent
}

应用场景3-抽离state

一般写法:

class Form extends React.Component{
        state = {user:"",psw:""}
        onUserChange = (e)=>{
            this.setState({user: e.target.value})
        }
        onPswChange = (e)=>{
            this.setState({psw: e.target.value})
        }
    render(){
        return(
            <div>
                <div>
                   用户名:<input type="text" value={this.state.user} onChange={this.onUserChange}/>
                </div>
                <br/>
                <div>
                    密码:<input type="text"  value={this.state.psw} onChange={this.onPswChange}/>
                </div>
                <div>
                    <p>变动:</p>
                     <p>{this.state.user}|{this.state.psw}</p>
                </div>
            </div>
        )
    }
}

抽离state后的写法:

const wrapComponent = (OriginalComponent) => class extends Component{
	constructor(props) {
		super(props)
		this.state = {user:"",psw:""}
		this.onUserChange = (e)=>{
			this.setState({user: e.target.value})
		}
		this.onPswChange = (e)=>{
			this.setState({psw: e.target.value})
		}
	  }
   
	render(){
        const newProps={
			user:{
				value:this.state.user,
				onChange: this.onUserChange,
			},
			psw:{
				value:this.state.psw,
				onChange: this.onPswChange
			}	
		}
		return(
			<OriginalComponent {...this.props} {...newProps}/>
		)
	}
}
//Form.js
import wrapComponent from './WrapComponent'
function Form(props){
    return(
        <div>
            <div>
               用户名:<input type="text" {...props.user}/>
            </div>
            <br/>
            <div>
                密码:<input type="text"  {...props.psw}/>
            </div>
            <div>
                <p>变动:</p>
                 <p>{props.user.value}|{props.psw.value}</p>
            </div>
		</div>
    )
}
export default wrapComponent(Form)

image.png

应用场景4-反向继承

//WrapComponent.js
function wrapComponent(OriginalComponent){
	return class WrapComponent extends OriginalComponent{
		componentDidMount(){
			console.log(this.state)
			this.setState({
				count:1
			})
			setInterval(()=>{
				this.setState({count:this.state.count+1})
			}, 1000)
            //2.也可以继承其他。例如state,props,组件生命周期,以及渲染方法
            //下面是继承了一个生命周期
			super.componentDidMount()
		}
		
		render(){
			//1.继承render
			return super.render()
		}
	}
}
export default wrapComponent
//Counter.js
import wrapComponent from './WrapComponent'
class Counter extends React.Component {
	constructor(){
		super();
		this.state = {count : '无'}
	}
    componentDidMount(){
		console.log('有事吗?')
	}
	render(){
		return (
			<div>
				{this.state.count}
			</div>
		)
	}
}
export default wrapComponent(Counter)

image.png
默认只打印高阶组件里面的,只有当super了才会打印继承过来的。
image.png

应用场景5-利用反向继承劫持渲染

把高阶组件的render变换一下,现在只要当传过来的start为true时才会渲染

//WrapComponent.js
render(){
    if (this.props.start) {
        return super.render()
    } else {
        return null
    }
    //return super.render()
}
//App.js
import Counter from './Counter'
class App extends Component {
  render(){
    return(
      <Counter start={true}/>
    )
  }
}

多个参数

  • 有时候高阶组件只接收一个参数

    const AfterWrap = wrapComponent(SayHi);
    
  • 也可以接收多个参数,比如接收配置对象用于指定组件的数据依赖:

    //假设 "DataSource" 是个全局范围内的数据源变量
    const BlogPostWithSubscription = withSubscription(
      BlogPost,
      (DataSource, props) => DataSource.getBlogPost(props.id)
    );
    
    //传进来的第二个参数实际上是能获取并返回数据的函数
    function withSubscription(WrappedComponent, selectData) {
      return class extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
            data: selectData(DataSource, props)
          };
        }
     //...
        handleChange() {
          this.setState({
            data: selectData(DataSource, this.props)
          });
        }
      
        render() {
          return <WrappedComponent data={this.state.data} {...this.props} />;
        }
      };
    }
    

该示例具体的看这里https://react.docschina.org/docs/higher-order-components.html

参考

posted @ 2020-09-28 13:38  sanhuamao  阅读(527)  评论(0编辑  收藏  举报