React 入门:实战案例 TodoList 对组件的 props 进行限制

本文介绍如何使用prop-types库为React组件的Props设置类型和必要性限制,通过具体实例展示了如何确保组件接收到正确的Prop类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


本文实现对组件的 props 进行属性的类型和必要性的限制。

为什么要对 props 增加限制呢?是为了在他人使用我们编写、或者我们使用他人编写的的组件的时候,传入了错误的 props 属性类型,或者漏传了必要的属性,通过限制可以在控制台报出有意义的错误提示信息。

建议: 在实际开发工作中,给组件编写必要性的注释,或者单独编写开发文档,介绍组件的使用,并说明 props 属性的类型和必要性。

安装 prop-types 库

PropTypes 提供一系列验证器,可用于确保组件接收到的数据类型是有效的。当传入的 prop 值类型不正确时,浏览器控制台将会显示警告。

  • 通过 npm 安装
npm install prop-types
  • 通过 yarn 安装
yarn add prop-types

注意:出于性能方面的考虑,propTypes 仅在开发模式下进行检查。

给组件的 props 添加限制

下面我们对 TodoList 的组件接收的 props 进行类型和必要性的限制。

给 Header 组件添加限制

Header 组件接收一个函数类型的 addTodo 的 props 属性,而且是必须的。实现代码片段如下:

// file: src/components/Header/index.jsx

// 引入 prop-types 库
import PropTypes from "prop-types";

// 以静态属性的方式定义限制规则
static propTypes = {
  addTodo: PropTypes.func.isRequired,
};

给 List 组件添加限制

List 组件接收以下两个 props 属性:

  • TodoList:数组类型,且必须。
  • updateTodo:函数类型,且必须。

实现代码片段如下:

// file: src/components/List/index.jsx

// 引入 prop-types 库
import PropTypes from "prop-types";

// 以静态属性的方式定义限制规则
static propTypes = {
  todoList: PropTypes.array.isRequired,
  updateTodo: PropTypes.func.isRequired,
};

给 Item 组件添加限制

Item 组件接收以下 props 属性:

  • id:数字类型,且必须。
  • name:字符串类型,且必须。
  • done:布尔类型,且必须。
  • updateTodo:函数类型,且必须。

实现代码片段如下:

// file: src/components/Item/index.jsx

// 引入 prop-types 库
import PropTypes from "prop-types";

// 以静态属性的方式定义限制规则
static propTypes = {
  id: PropTypes.number.isRequired,
  name: PropTypes.string.isRequired,
  done: PropTypes.bool.isRequired,
  updateTodo: PropTypes.func.isRequired,
};

至此我们就完成了对相关组件的 props 的限制。

扩展: 上面的代码只对 props 进行了简单的限制,如果你想要了解更多限制规则,请参考 React 官方介绍 使用 PropTypes 进行类型检查

验证 props 限制

下面我们以 Item 组件为例来验证上面添加的 PropTypes 限制是否起作用。

验证 id,它的限制规则是 数字且必须,那么我们把 App.js 中的初始化数据中的 id 改为字符串,代码如下:

// file: src/App.js

// 初始化状态
state = {
  todoList: [
    { id: 1, name: "参加晨会", done: true },
    { id: "2", name: "A功能开发", done: true }, // 将这条 todo 的 id 改为字符串
    { id: 3, name: "B功能开发", done: false },
  ],
};

此时浏览器控制台报错如下:
在这里插入图片描述

其他组件的验证,可按照上面的方法进行。

完整代码

Header 组件完整代码

// file: src/components/Header/index.jsx

import React, { Component } from "react";
import PropTypes from "prop-types";
import { nanoid } from "nanoid";
import "./index.css";

export default class Header extends Component {
  // 对接收的 props 进行:类型、必要性的限制
  static propTypes = {
    addTodo: PropTypes.func.isRequired,
  };

  // 键盘事件的回调
  handleKeyUp = (event) => {
    // 解构赋值获取 keyCode, target
    const { keyCode, target } = event;
    // 判断是否是回车按键
    if (keyCode !== 13) return;
    // 添加的任务名称不能为空
    if (target.value.trim() === "") {
      alert("任务名称不能为空");
      return;
    }
    // 构建一个 Todo 对象
    const todoObj = { id: nanoid(), name: target.value, done: false };
    // 将 todoObj 传递给 App 组件
    this.props.addTodo(todoObj);
    // 清空输入
    target.value = "";
  };

  render() {
    return (
      <div className="todo-header">
        <input
          onKeyUp={this.handleKeyUp}
          type="text"
          placeholder="请输入你的任务名称,按回车键确认"
        />
      </div>
    );
  }
}

List 组件完整代码

// file: src/components/List/index.jsx

import React, { Component } from "react";
import PropTypes from "prop-types";
import Item from "../Item";
import "./index.css";

export default class List extends Component {
  // 对接收的 props 进行:类型、必要性的限制
  static propTypes = {
    todoList: PropTypes.array.isRequired,
    updateTodo: PropTypes.func.isRequired,
  };

  render() {
    const { todoList, updateTodo } = this.props;
    return (
      <ul className="todo-main">
        {todoList.map((todo) => {
          return <Item key={todo.id} {...todo} updateTodo={updateTodo} />;
        })}
      </ul>
    );
  }
}

Item 组件完整代码

// file: src/components/Item/index.jsx

import React, { Component } from "react";
import PropTypes from "prop-types";
import "./index.css";

export default class Item extends Component {
  // 对接收的 props 进行:类型、必要性的限制
  static propTypes = {
    id: PropTypes.number.isRequired,
    name: PropTypes.string.isRequired,
    done: PropTypes.bool.isRequired,
    updateTodo: PropTypes.func.isRequired,
  };

  state = { mouse: false }; //标识鼠标移入、移出

  // 鼠标移入、移出的回调
  handleMouse = (flag) => {
    return () => {
      this.setState({ mouse: flag });
    };
  };

  // 勾选、取消勾选某一个 Todo 的回调
  handleCheck = (id) => {
    return (event) => {
      this.props.updateTodo(id, event.target.checked);
    };
  };

  render() {
    const { id, name, done } = this.props;
    const { mouse } = this.state;
    return (
      <li
        style={{ backgroundColor: mouse ? "#eee" : "#fff" }}
        onMouseEnter={this.handleMouse(true)}
        onMouseLeave={this.handleMouse(false)}
      >
        <label className="container">
          <input
            type="checkbox"
            defaultChecked={done}
            onChange={this.handleCheck(id)}
          />
          <span>{name}</span>
        </label>
        <button
          className="btn btn-danger btn-sm"
          style={{ display: mouse ? "block" : "none" }}
        >
          删除
        </button>
      </li>
    );
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西涯三锋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值