When you connect with a cause, it's like falling in love.
When you connect with a cause, it's like falling in love.
随着 React 的新 Context API 出来,render props 模式再次发挥重要作用。本文将尝试深入理解 render props 的利弊,并结合高阶组件寻找合适的处理方式。
先看官方给出的简单例子:
<DataProvider render={data => (
<h1>Hello {data.target}</h1>
)}/>
加个 DataProvider
的简单实现,
class DataProvider extends React.Component {
state = { target: '' }
handleMouseMove = e => this.setState({ target: e.target.title })
render() {
return (
<div style={{ height: '1vh' }} onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
)
}
}
这里是将一个返回 React 元素的函数传给 DataProvider
的 props.render
,DataProvider
render 的时候调用 this.props.render(this.state)
渲染这个函数。
这也是“render props”名字的来源,而现在更流行的是“children props”,虽然依然沿用 render props 的说法。
Children props 即将 render 换为 children ,同时 JSX 中不需要显式写 chidlren ,所以成了这个样子:
<DataProvider>
{data => <h1>Hello {data.target}</h1>}
</DataProvider>
子组件通过 render props 传进父组件渲染,让父组件不再依赖子组件,达到重用父组件的目的,即依赖反转。
前面提到的“返回 React 元素的函数”,一看是不是跟无状态函数组件(Stateless Fuctional Component)的签名很接近。这么看:
<DataProvider>
{props => <h1>Hello {props.target}</h1>}
</DataProvider>
但不一样的地方在于 render props 只是一个普通函数,是直接函数调用。且 inline render props 可以跳过 DataProvider
直接访问其它父组件:
const App = props => (
<DataProvider>
{data => <h1>Hello {data.target} {props.target}</h1>}
</DataProvider>
)
这就造成了 DataProvider
不能优化为纯组件。这也是非常不好的习惯,一个解决方式是人为限制 render props 为 SFC 从而让只有一个数据来源。理想很美好,但没法强制所有人这么干。
如果将 render props 限制为传入子组件,其实很容易联想到高阶组件(Higher-Order Components)。高阶组件是一个函数,接受一个组件,返回新的组件。
所以可以用高阶组件包装起来,并隐藏 render props 接口。
const withData = Base => () => <DataProvider>{Base}</DataProvider>
const BaseTarget = props => <h1>Hello {props.target}</h1>
const EnhancedComponent = withData(BaseTarget)
const App = () => <EnhancedComponent />
这样就限制了 DataProvider
的使用方式。如果需要多方数据,可以修改 DataProvider
为 this.props.render({ ...this.props, ...this.state })
将其它数据作为 props 传入 DataProvider
。
const withData = Base => props => <DataProvider {...props}>{Base}</DataProvider>
const BaseTarget = props => <h1>Hello {props.target}</h1>
const EnhancedComponent = withData(BaseTarget)
const App = props => <EnhancedComponent {...props} />
「完」
评论没有加载,检查你的局域网
Cannot load comments. Check you network.