React 中渲染 Props 的概述
在 React 中使用渲染 Props 是一种有效重用代码的技术。根据 React 文档,“具有渲染 Props 的组件接受一个返回 React 元素的函数,并调用它而不是实现自己的渲染逻辑。” 为了理解这意味着什么,让我们看一下渲染 Props 模式,然后将其应用于几个简单的示例。
渲染 Props 模式
在使用渲染 Props 时,您将一个渲染函数传递给一个组件,该组件依次返回一个 React 元素。此渲染函数由另一个组件定义,接收组件共享通过渲染函数传递的内容。
这就是它的样子
class BaseComponent extends Component {
render() {
return <Fragment>{this.props.render()}</Fragment>;
}
}
假设我们的 App
是一个礼品盒,其中 App
本身是顶部的蝴蝶结。如果盒子是我们正在创建的组件,我们打开它,我们将公开使组件在 render()
调用后工作所需的 props、状态、函数和方法。

组件的渲染函数通常包含形成该组件 DOM 的所有 JSX 等。相反,此组件具有一个渲染函数 this.props.render()
,该函数将显示通过 props 传入的组件。
示例:创建计数器
查看 Kingsley Silas Chijioke (@kinsomicrote) 在 CodePen 上的笔 React 渲染 Props。
让我们做一个简单的计数器示例,根据单击的按钮增加或减少值。
首先,我们从创建一个将用于包装初始状态、方法和渲染的组件开始。有创意地,我们将此称为 Wrapper
class Wrapper extends Component {
state = {
count: 0
};
// Increase count
increment = () => {
const { count } = this.state;
return this.setState({ count: count + 1 });
};
// Decrease count
decrement = () => {
const { count } = this.state;
return this.setState({ count: count - 1 });
};
render() {
const { count } = this.state;
return (
<div>
{this.props.render({
increment: this.increment,
decrement: this.decrement,
count: count
})}
</div>
);
}
}
在 Wrapper
组件中,我们指定方法和状态,这些方法和状态会暴露给包装的组件。对于此示例,我们需要 increment
和 decrement
方法。我们的默认 count
设置为 0
。逻辑是根据触发的函数增加或减少 count
,从零值开始。
如果您查看 return()
方法,您会看到我们正在使用 this.props.render()
。正是通过此函数,我们从 Wrapper
组件传递方法和状态,以便被其包装的组件将使用它。
要将其用于我们的 App
组件,该组件将如下所示
class App extends React.Component {
render() {
return (
<Wrapper
render={({ increment, decrement, count }) => (
<div>
<div>
<h3>Render Props Counter</h3>
</div>
<div>
<p>{count}</p>
<button onClick={() => increment()}>Increment</button>
<button onClick={() => decrement()}>Decrement</button>
</div>
</div>
)}
/>
);
}
}
示例:创建数据列表
收益在于渲染 Props 的可重用能力,让我们创建一个可以用于处理从 API 获取的数据列表的组件。
查看 Kingsley Silas Chijioke (@kinsomicrote) 在 CodePen 上的笔 React 渲染 Props 2。
这次我们想要从包装器组件中得到什么?我们希望将我们想要渲染的数据的源链接传递给它,然后发出 GET
请求以获取数据。获取数据后,我们将其设置为组件的新状态并进行渲染以显示。
class Wrapper extends React.Component {
state = {
isLoading: true,
error: null,
list: []
};
fetchData() {
axios.get(this.props.link)
.then((response) => {
this.setState({
list: response.data,
isLoading: false
});
})
.catch(error => this.setState({ error, isLoading: false }));
}
componentDidMount() {
this.setState({ isLoading: true }, this.fetchData);
}
render() {
return this.props.render(this.state);
}
}
数据链接将作为 props 传递给 Wrapper
组件。当我们从服务器获取响应时,我们使用从服务器返回的内容更新 list
。组件挂载后会向服务器发出请求。
以下是 Wrapper
的使用方法
class App extends React.Component {
render() {
return (
<Wrapper
link="https://jsonplaceholder.typicode.com/users"
render={({ list, isLoading, error }) => (
<div>
<h2>Random Users</h2>
{error ? <p>{error.message}</p> : null}
{isLoading ? (
<h2>Loading...</h2>
) : (
<ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul>
)}
</div>
)}
/>
);
}
}
您可以看到我们传递链接作为 prop,然后我们使用 ES6 解构来获取 Wrapper
组件的状态,然后将其渲染。组件首次加载时,我们显示加载文本,一旦我们从服务器获取响应和数据,就会将其替换为项目列表。
此处的 App
组件是一个类组件,因为它不管理状态。我们可以将其转换为函数式无状态组件。
const App = () => {
return (
<Wrapper
link="https://jsonplaceholder.typicode.com/users"
render={({ list, isLoading, error }) => (
<div>
<h2>Random Users</h2>
{error ? <p>{error.message}</p> : null}
{isLoading ? (
<h2>Loading...</h2>
) : (
<ul>{list.map(user => <li key={user.id}>{user.name}</li>)}</ul>
)}
</div>
)}
/>
);
}
总结!
人们经常将渲染 Props 与 高阶组件 进行比较。如果您想走这条路,我建议您也 查看这篇文章 以及 Michael Jackson 关于此主题的 这篇有见地的演讲。
感谢您的帖子。
在我看来,这种技术仅在可能有多个表示组件使用包装器的相同逻辑时才相关。如果只有一个表示组件可能使用此逻辑,则使用此技术没有意义。
有道理吗?
您能为此建议其他用例吗?
谢谢
“假设我们的 App 是一个礼品盒,其中 App 本身是顶部的蝴蝶结。”那么 App 是什么?