React - children props与render props
在 React 中,当需要向组件内部动态传入带内容的结构时,有两种常用方案:children props 和 render props。
1. children props 方式
children props
是通过组件标签体来传入结构,这是最简单直接的方式。
局限性:如果传入的子组件(如 B 组件)需要使用父组件(A 组件)内部的数据,这种方式就无法实现了。
js
// 父组件使用方式
<A> <B>这是要传入A组件的内容</B> </A>
// A组件内部获取方式
class A extends React.Component {
render() {
return (
<div>
{/* 直接渲染传入的内容 */}
{this.props.children}
</div>
);
}
}
2. render props 方式
render props
是通过组件的属性传入一个函数 ,这个函数返回要渲染的结构,并且可以携带父组件的数据:
kotlin
<A render={(data) => <C data={data}></C>}></A>
A组件: {this.props.render(内部state数据)}
C组件: 读取A组件传入的数据显示 {this.props.data}
jsx
import { Component } from "react";
import "./index.css";
export default class A extends Component{
state = {
verse:'露从今夜白'
}
render(){
console.log('render-父亲')
return(
<div className='Father'>
<h1>我是Father</h1>
<B><C/></B>
<B render={(name)=><D name={name}/>} />
</div>
)
}
}
class B extends Component{
state = {name:'我的未来式'}
render(){
console.log('render-B',this.props)
let {name} = this.state
return(
<div className='Son' >
<h1>我是B</h1>
{this.props.children}
{/* 只有当render存在时才调用,渲染第一个时,无该方法 */}
{this.props.render && this.props.render(name)}
</div>
)
}
}
class C extends Component{
render(){
console.log('render-孙子')
// let { name } = this.props
return(
<div className='grandson' >
<h1>我是C</h1>
<p>第一种方法渲染</p>
</div>
)
}
}
class D extends Component{
render(){
let { name } = this.props
console.log('render-孙子',name)
return(
<div className='grand' >
<h1>我是D</h1>
<p>获取第二种方法的name,name为:{name}</p>
</div>
)
}
}
总结:两种方式的对比
-
children props:
- 适用于简单场景,只是单纯传入要渲染的内容
- 使用方式:通过组件标签体传入
- 局限性:无法将父组件内部数据传递给子组件
-
render props:
- 适用于需要共享组件内部状态和方法的场景
- 使用方式:通过组件属性传入一个返回 JSX 的函数
- 优势:可以将组件内部的数据和方法传递给子组件,实现组件间的数据共享
- 灵活性高,可以根据需要渲染不同的子组件结构
示例:
jsx
import React from 'react';
// 1. children props 示例
class ChildrenExample extends React.Component {
render() {
return (
<div className="border p-4 m-2">
<h3>Children Props 示例</h3>
{/* 直接渲染通过标签体传入的内容 */}
{this.props.children}
</div>
);
}
}
// 2. Render props 示例 - 提供数据的组件
class DataProvider extends React.Component {
state = {
user: {
name: "张三",
age: 25,
hobbies: ["篮球", "读书", "旅行"]
},
theme: "light"
};
// 切换主题的方法
toggleTheme = () => {
this.setState(prevState => ({
theme: prevState.theme === "light" ? "dark" : "light"
}));
};
render() {
// 将内部状态和方法通过render函数传递出去
return this.props.render({
...this.state,
toggleTheme: this.toggleTheme
});
}
}
// 使用数据的组件1
class UserInfo extends React.Component {
render() {
const { user } = this.props;
return (
<div className="p-3">
<h4>用户信息</h4>
<p>姓名:{user.name}</p>
<p>年龄:{user.age}</p>
<p>爱好:{user.hobbies.join("、")}</p>
</div>
);
}
}
// 使用数据的组件2
class ThemeSwitcher extends React.Component {
render() {
const { theme, toggleTheme } = this.props;
return (
<div className="p-3">
<h4>主题切换</h4>
<p>当前主题:{theme}</p>
<button onClick={toggleTheme} className="btn btn-primary">
切换主题
</button>
</div>
);
}
}
// 主应用组件
class App extends React.Component {
render() {
return (
<div className="container mt-4">
<h2>React 动态传入内容示例</h2>
{/* Children Props 使用 */}
<ChildrenExample>
<p>这是通过children props传入的内容</p>
<button className="btn btn-success">这是一个按钮</button>
</ChildrenExample>
{/* Render Props 使用 */}
<div className="border p-4 m-2">
<h3>Render Props 示例</h3>
<DataProvider render={(data) => (
<div className="d-flex gap-4">
<UserInfo user={data.user} />
<ThemeSwitcher theme={data.theme} toggleTheme={data.toggleTheme} />
</div>
)} />
</div>
</div>
);
}
}
export default App;
在实际开发中,根据是否需要共享数据来选择合适的方式。如果需要组件间的数据共享,render props 是更好的选择。另外,随着 React Hooks 的普及,一些原本需要用 render props 解决的问题,现在也可以通过自定义 Hooks 来更简洁地实现。