react的一些巧思和ts

18 篇文章 1 订阅
本文介绍了React中的几个高级用法,包括React.Children.map用于遍历和操作子组件,React.memo用于优化组件渲染,createPortal创建跨容器的模态对话框,以及如何动态设置CSS样式和利用可选链处理可能不存在的方法调用。此外,还讨论了TypeScript在React开发中的应用,如类型推断、泛型和类型断言等。
摘要由CSDN通过智能技术生成

----------------- 这里是以前没见过的一些巧思,很有趣-----------------

== React.Children=============

又是没见过的东西【Children.map】【memo的第二个参数】【createPortal】
【1】React.Children.map(children, function[(thisArg)])
 在 ​children​ 里的每个直接子节点上调用一个函数,并将 ​this​ 设置为 ​thisArg​。如果 ​children​ 是一个数组,它将被遍历并为数组中的每个子节点调用该函数。如果子节点为 ​null​ 或是 ​undefined​,则此方法将返回 ​null​ 或是 ​undefined​,而不会返回数组。
【2】React.memo 是 React 16.6 新的一个 API,用来缓存组件的渲染,避免不必要的更新,其实也是一个高阶组件,与 PureComponent 十分类似,但不同的是, React.memo 只能用于函数组件 。默认情况下其只会对 props 做浅层对比,遇到层级比较深的复杂对象时,表示力不从心了。对于特定的业务场景,可能需要类似 shouldComponentUpdate 这样的 API,这时通过 memo 的第二个参数来实现
【3】使用 portal 创建一个浮动在页面其余部分之上的模态对话框,即使呼出对话框的组件位于带有 overflow: hidden 或其他干扰对话框样式的容器中。portal 允许组件将它们的某些子元素渲染到 DOM 中的不同位置。这使得组件的一部分可以“逃脱”它所在的容器。例如组件可以在页面其余部分上方或外部显示模态对话框和提示框。

```
{createPortal(
    <p>这个子节点被放置在 document body 中。</p>,
    document.body
  )}

{showModal && createPortal(
<ModalContent onClose={() => setShowModal(false)} />,
document.body
)}


==js更改css样式,给css设置动态值==
var style = document.styleSheets[0];
style.insertRule(`@keyframes scroll{0%{ transform: translateX(-${width}px); }100%{ transform: translateX(0px)`, 9);//写入样式

 1. 
 
可以代替无限条件判断控制页面显示的语句
		active 列表
		{ key: 'current', label: '当前负荷', icon: <ProjectOutlined /> },
        { key: 'calculation', label: '负荷计算', icon: <FundProjectionScreenOutlined /> },
        { key: 'history', label: '历史计算', icon: <HistoryOutlined /> },

{ { current: , calculation: , history: , }[active] }
``` ********************************* 2. test?.() 函数调用时如果被调用的方法不存在,使用可选链可以使表达式自动返回undefined而不是抛出一个异常。
let result = someInterface.customMethod?.();
  1. 判断图片不存在的情况
    简单粗暴的判断图片是否同时存在宽度和高度即可,省去了promise的处理过程
// 判断图片是否存在
export const isImgUrl = function(imgUrl: string) {
  const imgObj = new Image(); //判断图片是否存在
  imgObj.src = imageURL(imgUrl);
  return Boolean(imgObj.width && imgObj.height);
}

4.使用自定义属性和冒泡特性
之前觉的没有必要使用自定义属性,但是真遇到要使用的场景是真懵,顺便记录一下冒泡特性的应用
定义:
data-xxx=‘xxxx’

<div className={styles.chartul} onClick={handleClick}>
 		<li className={styles.charli} id = 'look' data-li = {item.id}>编辑/查看图表信息</li>
     <li className={styles.charli} id = 'del' data-li = {item.id}>删除图表</li>
 </div>

使用:
e.target.dataset.xxx

const handleClick = (e: any) => {
        console.log(e.target.dataset.li)
        if (e.target?.id === 'look') {

        } else {

        }
  }
  1. 是一个实用的小工具—让表头根据表头文字和每个内容自适应宽度
/**
 * 表头长度自适应
 * 快速切换表头时,防止表头无法即使更新,所以换成异步
 * setTimeout(() => {
        setData(formatData(res));
        setColumn(columns[type]);
        setOldCol(columns[type]);
      }, 200)
 */
export const mergedColumns = (columns: any, groupItems: any[]) => {
  const tableWidth: number = toNumber(document.getElementById('deviceID')?.style.width) || 0;
  const col = columns?.map((column: any) => {
    if (column?.key === 'option') return column; // 如果是操作按钮,不改变宽度
    if (column?.width && isNumber(column?.width)) {
      column.width =
        isNumber(column?.width) && Math.max(column?.width, tableWidth / columns?.length);
      return column;
    }
    return {
      ...column,
      width: Math.floor(tableWidth / columns?.length),
    };
  });
  //判断是否有数据源,是否根据宽度自适应
  const widthMap = new Map(); //每个属性最大长度
  groupItems?.forEach((target: any) => {
    for (const key in target) {
      if (target.hasOwnProperty(key)) {
        const keyWidth = getTextWidth(target[key]) + 75; //文字的长度
        const curValue = widthMap.get(key) || 0;
        widthMap.set(key, Math.max(curValue, keyWidth));
      }
    }
  });
  col?.forEach((item: any) => {
    const textWidth = getTextWidth(item.title); //表头标题长度
    item.width = Math.ceil(Math.max(textWidth + 75, widthMap.get(item.dataIndex))) || 90;
    widthMap.set(
      item.dataIndex,
      item.width, // 找到最大长度(代码内部的长度, 内容文字最大长度, 标题最大长度)
    );
  });
  return col;
  // setColumnNew(col);
};
  1. y!.toLowerCase(); // y 经过函数校验后不可能是 undefined,我们可通过非空断言告知 TS
  2. transform.match(/translate\((\d+),(\d+)\)/); ===>{ x: parseInt(translate[1]), y: parseInt(translate[2]) }
    拿出字符串里想要的特性位置的数值

----------------这里是在react项目中使用ts的一些整理,很烦

常见的元素属性类型: HTML属性类型:HTMLAttributes 按钮属性类型:ButtonHTMLAttributes
表单属性类型:FormHTMLAttributes 图片属性类型:ImgHTMLAttributes
输入框属性类型:InputHTMLAttributes 链接属性类型:LinkHTMLAttributes
meta属性类型:MetaHTMLAttributes 选择框属性类型:SelectHTMLAttributes
表格属性类型:TableHTMLAttributes 输入区属性类型:TextareaHTMLAttributes
视频属性类型:VideoHTMLAttributes SVG属性类型:SVGAttributes
WebView属性类型:WebViewHTMLAttributes

常见的标签及其类型: a: HTMLAnchorElement; body: HTMLBodyElement; br:
HTMLBRElement; button: HTMLButtonElement; div: HTMLDivElement; h1:
HTMLHeadingElement; h2: HTMLHeadingElement; h3: HTMLHeadingElement;
html: HTMLHtmlElement; img: HTMLImageElement; input: HTMLInputElement;
ul: HTMLUListElement; li: HTMLLIElement; link: HTMLLinkElement; p:
HTMLParagraphElement; span: HTMLSpanElement; style: HTMLStyleElement;
table: HTMLTableElement; tbody: HTMLTableSectionElement; video:
HTMLVideoElement; audio: HTMLAudioElement; meta: HTMLMetaElement;
form: HTMLFormElement;

使用React.FC 声明函数组件和普通声明的区别:
React.FC显式的定义了返回类型,其他方式是隐式推导的
React.FC对静态属性:displayName.propTypes, 提供了类型检查和自动补全
React.FC为children提供了隐式的类型(ReactElement|null)

函数组件在定义时,不知道props的类型,只有调用时才知道,那就还是用泛型来定义props的类型。
使用function定义的函数组件:
–1

定义组件:function Test<P>(props: P) {}
使用组件: 
定义props类型 type IProps = {name: string};
调用组件 <Test<IProps> name="test" />

–2

定义组件:
interface ActionProps {
  onEdit?: (e?: any) => void; // 编辑
  onDel?: (e?: any) => void; // 删除
}
const Action: React.FC<ActionProps> = () => {}
使用组件:<Action />

使用箭头函数定义的函数组件:必须使用extends关键字来定义泛型参数才能被成功解析
const MyComponent =

(props: P) {}

Ts是静态类型分析工具,TS不会执行JS代码,但并不是说TS内部没有执行逻辑

Ts提供了:
iinterface和type关键字,供定义自己的类型,之后能像使用基本类型一样使用自己定义的类型
type类型不能二次编辑,interface可以随时扩展
在定义公共API时,使用interface,这样可以方便使用者继承接口,这样允许使用声明合并来拓展它们
在定义组件属性(props)和状态(state)时,建议使用type,因为type约束性更强。

各种逻辑运算符,&,|等,供我们对类型进行操作,从而生成新的类型
泛型,允许在定义的时候不具体指定类型,而且泛泛说一种类型,并在函数调用的时候再指定具体的参数类型

接口:
定义规范标准,用于复用

泛型:对类型进行编程。其实不管是用于类还是用于函数,核心思想都是:把类型当一种特殊的参数传入进去
T是一个抽象类型,只有调用的时候才确定它的值。T可以是任何类型,所以如果不做限制,针对某一个类型操作时会报错。
function id(arg: T): T {
return arg;
}
什么时候使用泛型:
当你的函数,接口或类:
需要作用到很多类型的时候
需要被用到很多地方的时候

any:TS对于标记为any类型的变量,是没有进行类型检查而直接通过编译阶段的检查。
void: 表示没有任何类型,声明为void类型的变量,只能赋予undefined和null。
nerver: 表示永远不会有值。是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。

枚举 enum
可以给一组数值,赋予名字,这样对开发者比较友好。可以理解枚举就是一个字典。
可以反向映射,可以通过Enum[‘key’]的形式获取到对应的值value.

类型断言:可以用来手动指定一个值的类型。可以使用断言(as 关键字)来定义一个值的类型
const getStrLength = (target: string | number): number => {
if ((target as string).length) {
return (target as string).length;
} else {
return target.toString().length;
}
};
并不是类型转换,断言成一个联合类型中不存在的类型时不允许的

== ts 中没有办法直接动态取object的值,会报错元素隐式具有 “any” 类型,因为类型为 “string” 的表达式不能用于索引类型==
ts真的好烦人-----
解决方法:
定义对象的时候,接口加上

export interface BuildObjecProps {
  [key: string]: any, // 字段扩展声明
}; 

类型“(string | undefined)[]”的参数不能赋给类型“SetStateAction<CheckboxValueType[]>”的参数。
解决办法:
给接口设定一个必传属性,就不会有undefined的情况。

interface Person {
  name:string,
  age?:string,
  gender?:string,
  occupation?:string,
}

“An expression of type ‘void’ cannot be tested for truthiness”
主要是指检查条件无法判断是否是真,
遇到的场景:if(func()) ,func没有return

Expected an assignment or function call and instead saw an expression

主要是指函数以表达式的形式出现
遇见的场景:test1 && func(test1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值