January 20, 2022
By: wang

Recat组件

一、认识recat

元素是构成 React 应用的最小单位,它用于描述屏幕上输出的内容。

const element = <h1>认识 Recat!</h1>

// 根节点
ReactDOM.render(element, document.getElementById("root"));

它被称为 JSX, 一种 JavaScript 的语法扩展。 我们推荐在 React 中使用 JSX 来描述用户界面。 JSX 是在 JavaScript 内部实现的。

const myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));

// 由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性。

二、recat组件

组件就是封装一个方法用来更好的管理元素

const HelloMessage = (props) => {
  return <h1>{props.name}</h1>;
};
const element = <HelloMessage name="Hello, Recat !" />;

2.1 组件组合

const Name = (props) => {
  return <h3>{props.data}</h3>;
};

const Sex = (props) => {
  return <h3>{props.data}</h3>;
};

const Age = (props) => {
  return <h3>{props.data}</h3>;
};

const User = (props) => {
  return <div>{props.children}</div>;
};

const element = (
  <User>
    <Name data="小明" />
    <Sex data="男" />
    <Age data="19" />
  </User>
);

ReactDOM.render(element, document.getElementById("root"));

// 多参数解构
const User = (props) => {
  const { title, children } = props;

  return (
    <div>
      <h1>{title}</h1>
      {children}
    </div>
  );
};

三、recat组件设计

3.1 单一职责:一个类只负责一件事情

  • 提高可复用性. 功能越单一可复用性越高, 就比如一些基础组件

高内聚(组件‘专一’的执行某一件事,保证最大化独立) → 广义

低耦合(不让外部元素来访问组件内部的细节)

对于入门者来说不要重复原则更有用, 不要偷懒/多思考/重构/消除重复代码, 你的能力就会慢慢提升

3.2容器组件和展示组件分离

展示组件是一个只关注展示的'元件', 为了可以在多个地方被复用, 它不应该耦合'业务/功能', 或者说不应该过渡耦合. 像antd这类组件库提供通用组件显然就是'展示组件'

对于展示组件,我们要以一种'第三方组件库'的标准来考虑组件的设计

3.3 antd源码浅析(3.x)

学习antd组件设计思路(antd icon组件源码)

import * as React from 'react';
// classnames主要是为组件提供动态css功能,方便向React之类的应用提供状态编程
import classNames from 'classnames';
// omit作用就是过滤掉对象中不需要的属性,避免把不必要的属性传递下去
import omit from 'omit.js';

// 参数校验 好处:确保你接收到的数据是有效的 -> tjs写法
export interface IconProps {
  type: string; // 图标类型必须为string
  className?: string; // className类型必须为string
  title?: string; // title类型必须为string
  onClick?: React.MouseEventHandler<any>; // onClick类型必须为React.MouseEventHandler
  spin?: boolean; // 是否有旋转动画类型必须为boolean
  style?: React.CSSProperties; // style类型必须为React.CSSProperties
  //  ? 代表参数可选
}

const Icon = (props: IconProps) => {
  const { type, className = '', spin } = props;
  const classString = classNames({
    anticon: true,
    'anticon-spin': !!spin || type === 'loading',
    [`anticon-${type}`]: true,
  }, className);
  return <i {...omit(props, ['type', 'spin'])} className={classString} />;
};

export default Icon; 

可以看到Antd使用 <i> 标签来实现Icon组件,首先通过 IconProps 校验参数,然后组合 className ,默认添加 anticon ,判断 spin 属性,选择是否添加 anticon-spin ,接着添加 anticon-${type}属性,生成 className ,通过 omit 过滤掉 type , spin 属性,因为这俩属性对于 <i> 标签是没有意义的

举个栗子

<Icon type="question" style={{ fontSize: 16 }} />

生成的HTML代码

<i class="anticon anticon-question" style="font-size: 16px;"></i>

3.3插曲(1)

// classnames简单讲解
var classNames = require('classnames');
classNames('foo', 'bar'); // => 'foo bar'

classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'

// 不同的参数类型
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'

// 忽略错误的数据类型
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'

// 数组参数
var arr = ['b', { c: true, d: false }];
classNames('a', arr); // => 'a b c'

// recat类似写法
<div className={`foo ${ ? 'bar' : ''}`} />

3.3插曲(2)

var omit = require('omit.js');
omit({ name: 'Benjy', age: 18 }, [ 'name' ]); // => { age: 18 }

3.3插曲(3)

User.propTypes = {
  num: PropTypes.string
};

3.4插曲(4)

const Name = (props) => {
  const { name = "小李" } = props;
  return <h3>{name}</h3>;
};

ReactDOM.render(
  <>
    <Name name="小明" />
    <Name />
  </>,
  document.getElementById("root")
);
Tags: recat