renderProps使用

2,031 阅读3分钟

介绍和使用render props

什么是render prop

官方解释:render prop是一种在React组件之间使用一个值为函数的prop共享代码的技术 即使用了render这个prop的组件,接受一个函数来渲染元素,即父组件控制这部分的显示内容,而不是组件内部去实现自己的渲染逻辑。而父组件渲染的元素使用的数据是子组件内部控制的状态。 比如下面这个例子:

    <SearchList render={ data => ({
        data.map(item => <li key={item.id}>{item.name}</li>)
    })}/>

data即为SearchList组件内部的state。

为什么要使用render prop

试想下面这种场景: 实现一个组件,用户边输入,边搜索,搜索结果展示为一个列表 实现思路:

  1. 首先需要一个输入框和一个结果列表
  2. 使用debounce,间隔一段时间请求一次,渲染结果

export default class SearchList extends React.Component {
    constructor(props) {
        super(props);
        this.lastFetchId = 0;
        this.handleSearch = debounce(this.handleSearchB, 600);
        this.state = {
            value: '',
            optionList: [], // 可选列表
        };
    }
    onChange = (e) => {
        const value = e && e.target && e.target.value;
        this.handleSearch(value);
    }
    handleSearch = async (val) => {
        if (val) {
            this.lastFetchId += 1;
            const fetchId = this.lastFetchId;
             if (fetchId !== this.lastFetchId) {
                    return;
            }
            // 此处请求并处理结果
        }
    }
    render() {
        const { value, optionList } = this.state;
        return (
            <div className='content'>
                    <input type="text" value={value} onChange={this.onChange} placeholder="请输入"/>
                    <ul className="search-list">
                        {
                            optionList.map(item => (
                            <li className="item" key={item.id}>{item.name}</li>
                        }
                    </ul>
            </div>
        );
    }
}

上面实现了基本的功能,请求防抖和列表展示; 下面改动一下需求:

如果一个页面需要显示的是商品列表,另一个页面显示的品牌列表,展示的形式是一样的,但是因为接口的不同,需要展示的内容可能不一样。比如品牌列表需要展示品牌名,品牌知名度,商品列表需要展示商品名称,商品属性等信息;对于品牌,如果返回结果为空,则展示用户输入的品牌,并添加此品牌保证他始终能搜到结果。

你可能会想到把列表放到父组件去维护,渲染的时候采用children的方式,这是一种方法,因为父组件本身也需要使用列表数据,但是列表的处理逻辑更多的在子组件中,个人觉得这种处理方式并没有达到组件封装的目的。

这样就可以用到render prop来解决了

商品列表:

    <SearchList render={ data => ({
        data.map(item => <li key={item.id}>{item.goodsName}({item.speciations})</li>)
    })}/>

品牌列表:

    <SearchList render={ (data, value) => ({
        (data.length === 0 && val ? [{
            id: '',
            brandName: val,
        }] : data).map(item => <li key={item.id}>{item.brandName}</li>)
    })}/>

修改一下SearchList组件

render () {
    <ul className="search-list">
        {this.props.render(optionList)}
    </ul>
}

总结

总结:render prop是一个用于告知组件需要渲染什么内容的函数prop,而具体的使用场景就是一个组件渲染的部分,需要父组件决定,虽然大多数场景我们可以通过使用children prop的方式来实现,但当父组件需要渲染的部分的数据依赖子组件内部状态时,就需要使用render prop了,更直白的说,就是这个组件的基础功能是提供可变数据源的时候,具体展示可以从外部注入。

可变数据源组件:自己不知道要渲染什么,只是一个基础数据提供者