React@16.x(16)Render Props

发布于:2024-06-02 ⋅ 阅读:(100) ⋅ 点赞:(0)

1,问题描述

当使用组件时,标签中的内容,会被当做 props.children 来渲染:

子组件:

import React, { PureComponent } from "react";

export default class MyComponent extends PureComponent {
    state = {
        x: 0,
        y: 0,
    };
    render() {
        return <div>{this.props.children}</div>;
    }
}

父组件使用:

import React from "react";
import MyComponent from "./MyComponent";

export default function index() {
    return (
        <div>
            <MyComponent>
                <h2>1次使用</h2>
            </MyComponent>
            <MyComponent>
                <h2>2次使用</h2>
            </MyComponent>
        </div>
    );
}

现在的需求:父组件中如何使用子组件的状态?

2,解决方式

2.1,Render Props

注意到在子组件中默认渲染的是 props.children,那如果像上下文 <ctx.Consumer></ctx.Consumer> 一样,通过函数参数来传递指定内容,就可以解决了。

所以,props.children 变成函数即可

import React, { PureComponent } from "react";

export default class MyComponent extends PureComponent {
    state = {
        x: 1,
        y: 2,
    };
    render() {
        return <div>{this.props.children(this.state)}</div>;
    }
}

使用

import React from "react";
import MyComponent from "./MyComponent";

export default function index() {
    return (
        <div>
            <MyComponent>{(childrenState) => <h2>{childrenState.x}</h2>}</MyComponent>
            <MyComponent>{(childrenState) => <h2>{childrenState.y}</h2>}</MyComponent>
        </div>
    );
}

另外,一般这种情况不会用 props.children,而是使用约定俗成的 props.render 来表示。

// 子组件
<div>{this.props.render(this.state)}</div>;

// 父组件
<MyComponent render={(childrenState) => <h2>{childrenState.x}</h2>} />

注意,因为子组件 extends PureComponent,所以父组件应该将这个函数单独声明才行,否则每次都会重新渲染。(具体原因看这篇文章

修改父组件如下:

import React from "react";
import MyComponent from "./MyComponent";

const renderA = (childrenState) => <h2>{childrenState.x}</h2>;

export default function index() {
    return (
        <div>
            <MyComponent render={renderA}></MyComponent>
        </div>
    );
}

2.2,HOC

高阶组件也能解决这个问题,但相比 Render props 有点繁琐。

import React, { PureComponent } from "react";

export default function withState(Comp) {
    return class MyComponent extends PureComponent {
        state = {
            x: 1,
            y: 2,
        };

        render() {
            return <Comp {...this.props} x={this.state.x} />;
        }
    };
}

父组件使用

import React from "react";
import withState from "./withState";

function ChildA(props) {
    return <h2>{props.x}</h2>;
}

const ChildStateA = withState(ChildA);

export default function index() {
    return (
        <div>
            <ChildStateA />
        </div>
    );
}

3,使用场景

可以看到,效果类似 vue中作用域插槽

所以大多的使用场景:某些组件的各个功能和处理逻辑相同,只是渲染的UI不同


以上。