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")
);