React classnames原理及测试用例

目录
  • 前言
  • classnames 的用法
  • 学会 classnames 的原理
  • 测试用例的使用
  • 总结

前言

本期的源码阅读任务是:

  • 学会 classnames 的用法
  • 学会 classnames 的原理
  • 测试用例的使用

源码地址:JedWatson/classnames: A simple javascript utility for conditionally joining classNames together (github.com)

classnames 的用法

Classname 是一个 JavaScript 库,它允许您有条件地将类名连接在一起。在构建 React 组件或需要根据某些条件动态生成类名时,它可能非常有用。

下面是一个如何使用 classnames 的例子:

import classnames from 'classnames';
const Button = ({ primary, size }) => {
  const classes = classnames('btn', {
    'btn-primary': primary,
    'btn-large': size === 'large',
    'btn-small': size === 'small',
  });
  return <button className={classes}>Click me</button>;
};

在上面的示例中,classnames 函数接受一个类名和一个将类名映射为布尔值的对象。如果给定类名的布尔值为 true,则该类名将包含在类名的最终列表中。如果值为 false,则不包括类名。

还可以将一个字符串作为第二个参数传递给类名,在这种情况下,如果值为 true,那么它将被添加到类名的最终列表中。

const classes = classnames('btn', primary && 'btn-primary');

学会 classnames 的原理

classnames 源码并不复杂,除去一些兼容性判断,主要功能实现的代码如下:

function classNames() {
  var classes = [];
  for (var i = 0; i < arguments.length; i++) {
    var arg = arguments[i];
    if (!arg) continue;
    var argType = typeof arg;
    if (argType === "string" || argType === "number") {
      classes.push(arg);
    } else if (Array.isArray(arg)) {
      if (arg.length) {
        var inner = classNames.apply(null, arg);
        if (inner) {
          classes.push(inner);
        }
      }
    } else if (argType === "object") {
      if (
        arg.toString !== Object.prototype.toString &&
        !arg.toString.toString().includes("[native code]")
      ) {
        classes.push(arg.toString());
        continue;
      }
      for (var key in arg) {
        if (hasOwn.call(arg, key) && arg[key]) {
          classes.push(key);
        }
      }
    }
  }
  return classes.join(" ");
}

主要工作原理如下:

  • 函数声明了一个名为 class 的空数组,该数组将用于存储生成的类名。
  • 然后,函数进入一个循环,循环遍历传递给函数的参数。对于每个参数,执行以下步骤:
  • 检查参数的类型。如果它是一个字符串或数字,添加到类数组。
  • 如果参数是数组,则函数检查它是否为非空。如果是,则函数以数组元素作为参数递归地调用自身,并将结果添加到类数组中。
  • 如果参数是一个对象,那么函数将检查它是否有一个 toString 方法,该方法不是本机 Object.Prototype.toString 方法。如果是这样,调用 oString 的结果将添加到类数组中。如果不是,函数将遍历对象自己的可枚举属性,并将属性名称添加到类数组中(如果它们的对应值为真)。
  • 循环结束后,将类数组合并到一个单独的字符串中,使用一个空格字符作为分隔符,并返回结果字符串。

测试用例的使用

className 库使用 Mocha 进行代码测试:

Mocha 是一个运行在 Node.js 和浏览器上的 JavaScript 测试框架。它用于编写和运行 JavaScript 代码的测试用例。

使用 Mocha 写测试用例的简单示例:

const assert = require("assert");
describe("myFunction", () => {
  it("should return the expected result", () => {
    assert.equal(myFunction(1, 2), 3);
  });
});
  • it 函数用于定义单个测试用例。
  • 断言模块用于验证函数是否返回预期的结果。

一些测试用例

describe('classNames', function () {
    // 测试能够识别具有真值得对象
    it('keeps object keys with truthy values', function () {
            assert.equal(classNames({
                    a: true,
                    b: false,
                    c: 0,
                    d: null,
                    e: undefined,
                    f: 1
            }), 'a f');
    });
    // 检查 classNames 函数是否正确地处理了其输入参数中的假值,并且只在生成的类名字符串中包含真值。
    it('joins arrays of class names and ignore falsy values', function () {
            assert.equal(classNames('a', 0, null, undefined, true, 1, 'b'), 'a 1 b');
    });
    // 这个测试用例检查 classNames 函数是否正确地处理了各种不同类型的参数
    it('supports heterogenous arguments', function () {
            assert.equal(classNames({a: true}, 'b', 0), 'a b');
    });
    // 这个测试用例检查 classNames 函数是否正确地从生成的类名字符串中删除了前导空格和尾随空格。
    it('should be trimmed', function () {
            assert.equal(classNames('', 'b', {}, ''), 'b');
    });
    // 这个测试用例检查 classNames 函数在调用时是否返回一个空字符串,该函数的唯一参数是一个空对象。
    it('returns an empty string for an empty configuration', function () {
            assert.equal(classNames({}), '');
    });
    // ... 省略部分测试用例
});

总结

Classname 非常有用,它能够根据应用程序的状态构建动态类名。避免编写冗长和重复的 if-else 语句来构建类名。同时,源码测试用例写得非常详尽,很有借鉴意义,可以用来参考给自己的代码写一些测试用例。

以上就是React classnames原理及测试用例的详细内容,更多关于React classnames测试用例的资料请关注我们其它相关文章!

(0)

相关推荐

  • Css-In-Js实现classNames库源码解读

    目录 引言 使用 源码阅读 兼容性 CommonJS AMD window 浏览器环境 实现 多个参数处理 参数类型处理 数组处理 对象处理 测试用例 Css-in-JS 示例 总结 引言 classNames是一个简单的且实用的JavaScript应用程序,可以有条件的将多个类名组合在一起.它是一个非常有用的工具,可以用来动态的添加或者删除类名. 仓库地址:classNames 使用 根据classNames的README,可以发现库的作者对这个库非常认真,文档和测试用例都非常齐全,同时还有有

  • React中classnames库使用示例

    目录 classnames的引入 引入 使用 Node.js, Browserify, or webpack: classnames函数的使用 数组的形式 ES6中使用动态类名 结合React一起使用 总结: classnames的引入 从名字上可以看出,这个库是和类名有关的.官方的介绍就是一个简单的支持动态多类名的工具库. 支持使用 npm, Bower, or Yarn 使用 npm安装 npm install classnames 使用 Bower安装 bower install clas

  • React通过classnames库添加类的方法

    React添加Class的方式 在vue中添加class是一件非常简单的事情: 你可以通过传入一个对象, 通过布尔值决定是否添加类: <button :class="{ active: isFlag, aaa: true}">按钮</button> 你也可以传入一个数组: <!-- 1.基本使用 --> <h2 :class="['aaa', 'bbb']">Hello Vue</h2> <!-- 2

  • React classnames原理及测试用例

    目录 前言 classnames 的用法 学会 classnames 的原理 测试用例的使用 总结 前言 本期的源码阅读任务是: 学会 classnames 的用法 学会 classnames 的原理 测试用例的使用 源码地址:JedWatson/classnames: A simple javascript utility for conditionally joining classNames together (github.com) classnames 的用法 Classname 是一

  • React Diff原理深入分析

    在了解Diff前,先看下React的虚拟DOM的结构 这是html结构 <div id="father"> <p class="child">I am child p</p> <div class="child">I am child div</div> </div> 这是React渲染html时的js代码   自己可以在babel上试试 React.createElemen

  • 深入理解React State 原理

    目录 问题:setState 到底是同步还是异步的? 类组件state setState原理揭秘 函数组件state 问题:setState 到底是同步还是异步的? 如果对 React 底层有一定了解,可以回答出 batchUpdate 批量更新概念,以及批量更新被打破的条件. 答案:有时是同步,有时是异步. 在 合成事件 和 生命周期函数 里是 异步 的在 原生事件 和 setTimeout.promise里是 同步 的 造成setState的异步并不是由内部的异步代码引起的,在本身的执行过程

  • React Fiber原理深入分析

    目录 为什么需要 fiber fiber 之前 fiber 之后 fiber 节点结构 dom 相关属性 tag key 和 type stateNode 链表树相关属性 副作用相关属性 flags Effect List 其他 lane alternate fiber 树的构建与更新 mount 过程 update 过程 总结 react16 版本之后引入了 fiber,整个架构层面的 调度.协调.diff 算法以及渲染等都与 fiber 密切相关.所以为了更好地讲解后面的内容,需要对 fib

  • React redux 原理及使用详解

    目录 概述 createStore创建store applyMiddleware 应用中间件 combineReducers 合并多个reducer dispatch 中间件 中间件的调用顺序 store redux 数据流 bindActionCreators compose enhancer 使用 redux 常遇见的问题 概述 一个状态管理工具 Store:保存数据的地方,你可以把它看成一个容器,整个应用只能有一个 Store. State:包含所有数据,如果想得到某个时点的数据,就要对

  • React Context原理深入理解源码示例分析

    目录 正文 一.概念 二.使用 2.1.React.createContext 2.2.Context.Provider 2.3.React.useContext 2.4.Example 三.原理分析 3.1.createContext 函数实现 3.2. JSX 编译 3.3.消费组件 - useContext 函数实现 3.4.Context.Provider 在 Fiber 架构下的实现机制 3.5.小结 四.注意事项 五.对比 useSelector 正文 在 React 中提供了一种「

  • 深入理解React Native核心原理(React Native的桥接(Bridge)

    在这篇文章之前我们假设你已经了解了React Native的基础知识,我们会重点关注当native和JavaScript进行信息交流时的内部运行原理. 主线程 在开始之前,我们需要知道在React Native中有三个主要的线程: shadow queue:负责布局工作 main thread:UIKit 在这个线程工作(译者注:UI Manager线程,可以看成主线程,主要负责页面交互和控件绘制的逻辑) JavaScript thread:运行JS代码的线程 另外,一般情况下每个native模

  • 详解React Fiber架构原理

    目录 一.概述 二.Fiber架构 2.1 执行单元 2.2 数据结构 2.3 Fiber链表结构 2.4 Fiber节点 2.5 API 2.5.1 requestAnimationFrame 2.5.2 requestIdleCallback 三.Fiber执行流程 3.1 render阶段 3.1.1 遍历流程 3.1.2 收集effect list 3.2 commit阶段 3.2.1 根据effect list 更新视图 3.2.2 视图更新 四.总结 一.概述 在 React 16

  • react hooks实现原理解析

    目录 react hooks 实现 Hooks 解决了什么问题 Hooks API 类型 首先接触到的是 State hooks 其次接触到的是 Effect hooks 最后接触到的是 custom hooks Hooks 实现方式 问题一:useState dispatch 函数如何与其使用的 Function Component 进行绑定 react hooks 实现 Hooks 解决了什么问题 在 React 的设计哲学中,简单的来说可以用下面这条公式来表示: UI = f(data)

随机推荐