React Props:从基础使用到高级组件封装

作为一名前端学习者,React 的组件化思想一直是我日常学习的核心,而 props 作为组件之间通信的核心桥梁,更是贯穿了从基础组件到高级封装的全过程。最近通过实现 Greeting、Modal、Card 三个组件,对 props 的使用有了更细致的感悟,今天就来和大家分享我的实战心得。

在前端开发(尤其是 React)中,props 是用来从父组件向子组件传递数据的一种机制。

简单理解:

  • props 就像函数的参数:调用一个函数时传入参数,组件被使用时也可以传入 props。
  • props 是只读的:子组件不能修改接收到的 props,只能读取和使用。
  • props 可以是任何类型:字符串、数字、对象、数组、函数,甚至其他 React 元素。

一、Greeting 组件

Greeting 组件用是来展示/实现props 基础使用、类型校验与默认值

1. props 基础接收与解构

props 是以参数的形式传入的,本质是个对象。用对象解构直接获取需要的属性:

javascript 复制代码
function Greeting(props) {
    // 解构获取 props 中的属性
    const {name, message, showIcon} = props;
    return (
        <div>
            {/* 条件渲染:当 showIcon 为 true 时显示图标 */}
            {showIcon && <span>👋</span>}
            <h1>Hello, {name} </h1>
            <p>{message}</p>
        </div>
    )
}

在使用组件时,我们只需像传递 HTML 属性一样传递 props 即可:

javascript 复制代码
// 传递完整属性
<Greeting name="张三" message="你好" showIcon />
// 只传递必传属性
<Greeting name="四"  />

有个小细节:showIcon 是一个布尔类型的 props,当我们只写属性名不赋值时,它的默认值就是 true,这是 React 的语法糖,非常便捷。

2. props 类型校验:避免传参错误

在团队开发中,经常会出现 props 类型不匹配的问题(比如把数字当成字符串传递),这时 prop-types 库就能帮我们做校验。

给 Greeting 组件做了明确的类型约定,指定了属性的类型和是否必传:

javascript 复制代码
import PropTypes from 'prop-types';

Greeting.propTypes = {
    name: PropTypes.string.isRequired, // 必传字符串,不传会报错
    message: PropTypes.string, // 可选字符串,非必传
    showIcon: PropTypes.bool, // 可选布尔值,非必传
};

其中 isRequired 关键字表示该属性是必传项,如果父组件没有传递,控制台会抛出警告信息,帮我们定位问题。

3. defaultProps:设置 props 默认值

有些 props 不是必传的,但我们希望它有一个默认值,这时候 defaultProps 就派上用场了。比如 Greeting 组件的 message 属性,我给它设置了默认的问候语:

javascript 复制代码
Greeting.defaultProps = {
    message: '圣诞节快乐',
};

当父组件没有传递 message 属性时,组件会自动使用这个默认值,就像我只传递 name="磊" 时,页面会显示默认的 "圣诞节快乐",大大提升了组件的灵活性。

二、Modal 组件

Modal 弹窗组件就是 props 高级用法的体现 ------ 它通过 props 传递自定义组件,实现了弹窗头部、底部的灵活定制,让组件的复用性大大提升。

1. 接收组件类型的 props

Modal 组件的核心需求是:头部、底部可自定义,中间区域支持插入任意内容。我通过 props 接收头部组件(HeaderComponent)和底部组件(FooterComponent),再在组件内部渲染它们:

javascript 复制代码
function Modal(props) {
    // 解构获取子组件和自定义头部、底部组件
    const {children, HeaderComponent, FooterComponent} = props;
    return (
        <div style={styles.overlay}>
            <div style={styles.modal}>
                {/* 渲染自定义头部组件 */}
                <HeaderComponent />
                <div style={styles.content}></div>
                {/* 渲染中间自定义内容(children) */}
                {children}
                {/* 渲染自定义底部组件 */}
                <FooterComponent />
            </div>
        </div>
    )
}

这里的 HeaderComponentFooterComponent 本质上是函数(React 组件本质是函数 / 类),通过 props 传递后,我们可以像使用普通组件一样直接渲染。

2. children props:组件的 "插槽"

在 Modal 组件中,children 是一个特殊的 props,它对应着组件标签之间包裹的所有内容,相当于 Vue 中的插槽。通过 children,我们可以给 Modal 插入任意 JSX 内容,实现中间区域的定制化:

javascript 复制代码
<Modal
    HeaderComponent={MyHeader}
    FooterComponent={MyFooter}
>
    {/* 这里的内容会被 children 接收并渲染 */}
    <p>这是一个弹窗</p>
    <p>你可以在这里显示任何JSX</p>
</Modal>

我们可以在这里打印一下props

而自定义的头部和底部组件,只需在父组件中定义好,再通过 props 传递给 Modal 即可:

javascript 复制代码
// 自定义弹窗头部
const MyHeader = () => {
    return (
        <h2 style={{margin:0,color:'red'}}>自定义标题</h2>
    )
}

// 自定义弹窗底部
const MyFooter = () => {
    return (
        <div style={{textAlign:'right'}}>
            <button 
              onClick={() => alert('取消')}
              style={{padding:'0.5rem 1rem'}}
            >取消</button>
        </div>
    )
}

这种方式让 Modal 组件不再是固定结构,而是可以根据业务需求灵活定制,大大提升了组件的复用性和扩展性。

三、Card 组件:props 结合 className,实现样式灵活扩展

Card 卡片组件是日常开发中使用频率极高的组件,我在实现它时,通过 props 接收自定义 className,实现了基础样式与自定义样式的结合,让卡片样式既统一又灵活。

1. 基础样式封装

首先,在 Card.css 中定义了卡片的基础样式,包括背景、圆角、阴影、内边距等,保证所有 Card 组件有统一的视觉风格:

css 复制代码
.card {
    background-color: #ffffff;
    border-radius: 12px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    padding: 20px;
    margin: 16px auto;
    max-width: 400px;
    transition: all 0.3s ease;
    overflow: hidden;
}

.card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}

2. props 接收 className,扩展自定义样式

为了让 Card 组件支持自定义样式,我在组件中接收 className 属性,并给它设置一个空字符串作为默认值,然后通过模板字符串将基础 className(card)和自定义 className 拼接起来:

javascript 复制代码
const Card = ({ children, className = '' }) => {
  return (
    <div className={`card ${className}`}>
      {children}
    </div>
  );
};

这样一来,当我们需要给某个卡片添加特殊样式时,只需传递自定义 className 即可:

javascript 复制代码
<Card className="user-card">
    <h2>张三</h2>
    <p>高级前端工程师</p>
    <button>查看详情</button>
</Card>

基础样式 card 保证了卡片的统一风格,自定义样式 user-card 可以满足个性化需求,这种方式既避免了样式冗余,又提升了组件的灵活性。同时,我也使用了 children props,让卡片内部可以插入任意内容,进一步提升了组件的复用性。

总结

通过实现 Greeting、Modal、Card 这三个组件,我对 React props 有了更全面的理解:

  1. 基础层面 (Greeting):props 是组件间传递数据的核心,配合 prop-types 类型校验和 defaultProps 默认值,能让组件更健壮、更易用;
  2. 高级层面 (Modal):props 不仅可以传递基本类型数据,还可以传递组件,结合 children 插槽,能实现高度定制化的组件封装;
  3. 样式层面(Card):props 接收 className,能实现基础样式与自定义样式的灵活结合,兼顾样式统一性和个性化。
相关推荐
汉堡大王95272 小时前
React组件通信全解:父子、子父、兄弟及跨组件通信
前端·javascript·前端框架
霍理迪2 小时前
CSS继承,优先级以及字体样式
前端·css
LeeHK2 小时前
在项目中调试vue2源码,watch,nextTick执行顺序梳理
前端
爱敲点代码的小哥2 小时前
json序列化和反序列化 和 数组转成json格式
java·前端·json
林太白2 小时前
2025 AI浪潮下的编程之路:我的天工项目与终身学习
前端·后端·trae
再花2 小时前
VitePress+Github Pages实现静态文档站
前端
Lsx_2 小时前
案例+图解带你一文读懂Svg、Canvas、Css、Js动画🔥🔥(4k+字)
前端·javascript·canvas
十一.3662 小时前
127-130 定时器的简介,切换图片练习,修改div移动练习,延时调用
前端·javascript·html
Jolyne_2 小时前
React下拉框接口请求hook封装
前端