这两种方法是React里的简单技术,但在具体业务中占有相应的使用场景,十分实用,下面简要的说明一下
Render Props
这是一种简单的技术,官网也有解释,简单理解就是将一个组件里的属性attribute
作为jsx语法的实现。如以下代码
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
| export class RenderPropsDemo extends Component { render(){ return <ToggleRenderProps render={({on, toggle, str}) => <div> { on && <h1>Hey zidea</h1> } { on && <h2>{str}</h2> } <button onClick={toggle}>隐藏/显示</button> </div> }/> } }
class ToggleRenderProps extends Component { state = { on:false } toggle = () => this.setState({ on:!this.state.on })
render() { const { render } = this.props; return render({ str: 'hehe', on: this.state.on, toggle: this.toggle, }) } }
|
从上面的例子可以看出,子组件 ToggleRenderProps
仅负责单一的传值和控制值和状态的功能,类似回调函数,把该控制的值回传给父组件 RenderPropsDemo
去使用。
任何被用于告知组件需要渲染什么内容的函数 prop 在技术上都可以被称为 “render prop”.
所以,你可以给属性取任意名字,例如 data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| export class RenderPropsDemo extends Component { render(){ return <ToggleRenderProps data={({on, toggle, str}) => <> ... </>}/>} }
class ToggleRenderProps extends Component { ... render() { return this.props.data({ ... }) } }
|
1 2 3 4 5 6 7 8 9
| export class RenderPropsDemo extends Component { render(){ return <ToggleRenderProps> {data={({on, toggle, str}) => <> ... </>} </ToggleRenderProps> } }
|
而子组件调用时,就是另一种概念了,可利用 this.props.children
的react自带api进行回传
1 2 3 4 5 6 7 8 9 10 11 12
| class ToggleRenderProps extends Component { state = { on:false } toggle = () => this.setState({ on:!this.state.on })
render() { return this.props.children({ str: 'hehe', on: this.state.on, toggle: this.toggle, }) } }
|
以上两种情况,一种在属性上定义的,类似具名函数,而包裹在元素内部,利用 children
进行调用的,类似匿名函数
Rener Props
的应用场景就很广泛了,很多库例如路由库React Router
,表单校验formik
都用了该方法。
正向代理HOC
在说反向代理之前,我们先说说正向代理,正向代理其实就是高阶组件 HOC,我们看看两者的区别:
普通HOC,即正向代理,简言之就是把一个组件外面包裹了一层新的组件,使其成为一个新组件
关于React的HOC和反向代理也可以参考这篇文章
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class AAA extends React.Component { constructor(props) { super(props) this.state = { num: 111 } }
render() { return <div num={this.state.num}>父组件AAA:{ this.state.num }</div> } }
const HOC = function (AAA) { return class extends React.Component { render () { return <div style={{border: 'solid 1px black'}}> <AAA {...this.props}/> </div> } } }
|
子组件也可改写为函数式写法:
1 2 3 4 5 6 7 8
| const HOC = AAA => props => { return <div style={{border: 'solid 1px black'}}> <AAA {...props}/> </div> }
export const Foo = HOC(AAA)
|
子组件改为装饰器写法,可以省略一步命名的操作,但实际项目中还需要在babel中单独另行配制装饰器语法
1 2 3 4 5 6 7 8 9 10
| @InheritanceInversionHOC export const HOC = function (AAA) { return class extends React.Component { render () { return <div style={{border: 'solid 1px black'}}> <AAA {...this.props}/> </div> } } }
|
反向代理 Inheritance Inversion HOC
相对于正向代理,则是继承组件自己本身进行重写
将上面的子组件进行重写
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 35 36 37 38 39 40 41
| class AAA extends React.Component { constructor(props) { super(props) this.state = { num: 111 } }
componentDidMount() { console.log("child component Did Mount") } clickComponent = () => console.log('clickComponent func')
render() { return <div num={this.state.num}>父组件AAA:{ this.state.num }</div> } }
const IIHOC = AAA => class extends AAA { constructor(props) { super(props) this.state = { num: 222 } }
componentDidMount() { console.log('IIHOC componentDidMount') this.clickComponent() }
render(){ return <div> <button onClick={this.clickComponent}>IIHoc点击见控制台,AAA组件的函数clickComponent在控制台执行了</button> {} <div><AAA /></div>
{} <h1>{super.render()}</h1> </div> } }
export const InheritanceInversionHOC = IIHOC(AAA)
|
反向代理的解析及实际作用
const IIHOC = AAA => class extends AAA {
中,extends AAA
是继承自己 AAA =>
本身
- 当然,
AAA =>
的名字AAA
是可以任意替换的,如Comp
- 生命周期函数
componentDidMount() { }
,因为是继承于自身,所以无论父子组件的生命周期函数均会执行
- 子组件里使用父组件的
this.clickComponent()
,直接使用即可,无需通过 props
进行传参
- 反向代理这种做法乍一看好像没有具体用途,但实际操作中,我们可用来做一个原来的复杂页面的多人同时开发,在一些在原有代码基础上开发,不能改变原来旧的代码,则可用反向继承实现二次渲染进行开发,能使新的功能独立成一个模块,方便维护