React+Ts,这样学起来确实简单!!!-程序员宅基地

技术标签: java  vue  js  react  javascript  

React这样的框架存在对应的声明文件,声明文件通过一些基础语法定义了一些类型,从而获取到TypeScript中诸如类型检查、接口提示等特性功能,也可以在自己用TS开发时避免自己写一些复杂的ts结构类型了,下面就来看一下React中定义ts语法如何使用。

茶已备好,只待君来!感谢关注 前端点线面 (>‿<),本号干货满满:
1.14个门类(100+篇原创)内容——又干又硬;
2.《前端百题斩》pdf——助力薪资double;
3.20+篇思维导图——知识系统化、记忆简单化;
加我进卧虎藏龙摸鱼群,一起划水一起嗨!!!

一、基础

俗话说的好:“授人以鱼不如授人以渔”,今天我也不知道自己的是“鱼”还是“渔”,就讲述一下自己这几天学习React语法的忐忑之路。

  1. 看typescript中文文档,然后总结了一波学习笔记

总结完之后,发现ts里面有类型推断的能力,很多在React这样的框架项目上根本用不上呀!!!

  1. 开启网上的疯狂搜索功能,看看有没有关于React这样的文章,搜索了一下,确实有一些,讲述有哪些React独有的类型;

卧槽,难道我为了用Ts又要记这些新的API吗?这不是坑爹吗?

  1. “柳暗花明又一村”,偶然的机会我点击了一个函数Reducer,神奇的发生了跳转,跳转到index.d.ts;

这不就是声明文件吗?然后认真分析Reducer

type Reducer<S, A> = (prevState: S, action: A) => S;

这不就是个函数的类型别名吗?其中两个S和A分别是泛型,然后返回值是S,那如果这样的话,我根本就不用记住很多这个类型了,当需要的时候直接点击该函数,跳转到对应的声明文件然后仔细研读一波就好了,哈哈,貌似就是这么回事。

【自己试了试,确实可以解决80%的问题】

不过为了提高开发效率,节省自己研究的成本,我还是写出几个常用的React中的ts语法,方便开发的时候套用。

二、 React中内置函数

React中内置函数由很多,我们就挑几个常用的来学习一下。

2.1 React.FC< P >

React.FC<>是函数式组件在TypeScript使用的一个泛型,FC就是FunctionComponent的缩写,事实上React.FC可以写成React.FunctionComponent。

import React from 'react';

interface demo1PropsInterface {
    attr1: string,
    attr2 ?: string,
    attr3 ?: 'w' | 'ww' | 'ww'
};

// 函数组件,其也是类型别名
// type FC<P = {}> = FunctionComponent<P>;
// FunctionComponent<T>是一个接口,里面包含其函数定义和对应返回的属性
// interface FunctionComponent<P = {}> {
//      // 接口可以表示函数类型,通过给接口定义一个调用签名实现
//      (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
//      propTypes?: WeakValidationMap<P> | undefined;
//      contextTypes?: ValidationMap<any> | undefined;
//      defaultProps?: Partial<P> | undefined;
//      displayName?: string | undefined;
// }
const Demo1: React.FC<demo1PropsInterface> = ({
    attr1,
    attr2,
    attr3
}) => {
    return (
        <div>hello demo1 {attr1}</div>
    );
};

export default Demo1;

2.2 React.Component< P, S >

React.Component< P, S > 是定义class组件的一个泛型,第一个参数是props、第二个参数是state。

import React from "react";

// props的接口
interface demo2PropsInterface {
    props1: string
};

// state的接口
interface demo2StateInterface {
    state1: string
};

class Demo2 extends React.Component<demo2PropsInterface, demo2StateInterface> {
    constructor(props: demo2PropsInterface) {
        super(props);
        this.state = {
            state1: 'state1'
        }
    }

    render() {
        return (
            <div>{this.state.state1 + this.props.props1}</div>
        );
    }
}

export default Demo2;

2.3 React.createContextuseContext、和useReducer中Ts使用

这三者经常一起使用,用来进行跨级组件间的数据传输,ts版如下所示:

  1. React.createContext

其会创建一个Context对象,当React渲染一个订阅了这个Context对象的组件,这个组件会从组件树中离自身最近的那个匹配的Provider中读取到当前的context值。【注:只要当组件所处的树没有匹配到Provider时,其defaultValue参数参会生效】

const MyContext = React.createContext(defaultValue);

const Demo = () => {
  return (
      // 注:每个Context对象都会返回一个Provider React组件,它允许消费组件订阅context的变化。
    <MyContext.Provider value={xxxxxx}>
      // ……
    </MyContext.Provider>
  );
}
  1. useContext

接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider>value prop 决定。语法如下所示:「const value = useContext(MyContext);」

import React, {useContext} from "react";
const MyContext = React.createContext('');

const Demo3Child: React.FC<{}> = () => {
    const context = useContext(MyContext);
    return (
        <div>
            {context}
        </div>
    );
}

const Demo3: React.FC<{}> = () => {
    const [state, dispatch] = useReducer(reducer, initialState);

    return (
        <MyContext.Provider value={'222222'}>
            <MyContext.Provider value={'33333'}>
                <Demo3Child />
            </MyContext.Provider>
        </MyContext.Provider>
    );
};
  1. useReducer

useState的替代方案,接收一个形如(state, action) => newState的reducer,并返回当前state以及其配套的dispatch方法。语法如下所示:「const [state, dispatch] = useReducer(reducer, initialArg, init);」

import React, {useReducer, useContext} from "react";

interface stateInterface {
    count: number
};
interface actionInterface {
    type: string,
    data: {
        [propName: string]: any
    }
};

const initialState = {
    count: 0
};

// React.Reducer其实是类型别名,其实质上是type Reducer<S, A> = (prevState: S, action: A) => S;
// 因为reducer是一个函数,其接受两个泛型参数S和A,返回S类型
const reducer: React.Reducer<stateInterface, actionInterface> = (state, action) => {
    const {type, data} = action;
    switch (type) {
        case 'increment': {
            return {
                ...state,
                count: state.count + data.count
            };
        }
        case 'decrement': {
            return {
                ...state,
                count: state.count - data.count
            };
        }
        default: {
            return state;
        }
    }
}

// React.createContext返回的是一个对象,对象接口用接口表示
// 传入的为泛型参数,作为整个接口的一个参数
// interface Context<T> {
//      Provider: Provider<T>;
//      Consumer: Consumer<T>;
//      displayName?: string | undefined;
// }
const MyContext: React.Context<{
    state: stateInterface,
    dispatch ?: React.Dispatch<actionInterface>
}> = React.createContext({
    state: initialState
});

const Demo3Child: React.FC<{}> = () => {
    const {state, dispatch} = useContext(MyContext);
    const handleClick = () => {
        if (dispatch) {
            dispatch({
                type: 'increment',
                data: {
                    count: 10
                }
            })
        }
    };
    return (
        <div>
            {state.count}
            <button onClick={handleClick}>增加</button>
        </div>
    );
}

const Demo3: React.FC<{}> = () => {
    const [state, dispatch] = useReducer(reducer, initialState);

    return (
        <MyContext.Provider value={
    {state, dispatch}}>
            <Demo3Child />
        </MyContext.Provider>
    );
};

export default Demo3;

三、React中事件处理函数

React中的事件是我们在编码中经常用的,例如onClick、onChange、onMouseMove等,那么应该如何用呢?

3.1 不带event参数

当对应的事件处理函数不带event参数时,这个时候用起来很简单,如下所示:

const Test: React.FC<{}> = () => {
    const handleClick = () => {
        // 做一系列处理
    };
    return (
        <div>
            <button onClick={handleClick}>按钮</button>
        </div>
    );
};

3.2 带event参数

老铁们可以试试,当事件处理函数待event参数的时候,如果不做任何处理,铁定报错,此时就按照第一节的方法论来试一试:

  1. 带上event参数,报错

const Test: React.FC<{}> = () => {
    // 报错了,注意不要这么写……
    const handleClick = event => {
        // 做一系列处理
        event.preventDefault();
    };
    return (
        <div>
            <button onClick={handleClick}>按钮</button>
        </div>
    );
};
  1. 点击onClick参数,跳转到index.d.ts文件

// onClick是MouseEventHandler类型
onClick?: MouseEventHandler<T> | undefined;

// 那MouseEventHandler<T>又是啥?原来是个类型别名,泛型是Element类型
type MouseEventHandler<T = Element> = EventHandler<MouseEvent<T>>;

// 那么泛型Element又是什么呢?其是一个接口,通过继承该接口实现了很多其它接口
interface Element { }
interface HTMLElement extends Element { }
interface HTMLButtonElement extends HTMLElement { }
interface HTMLInputElement extends HTMLElement { }
// ……
  1. 至此,就知道该位置应该怎么实现了

const Test: React.FC<{}> = () => {
    const handleClick: React.MouseEventHandler<HTMLButtonElement> = event => {
        // 做一系列处理
        event.preventDefault();
    };
    return (
        <div>
            <button onClick={handleClick}>按钮</button>
        </div>
    );
};
  1. 对于其它的事件一样,按照上述三个步骤,就可以一篇搞定,不需要进行所谓的死记硬背。

四、普通函数

普通函数是通用的,但是还是在这个位置提一下。

  1. 一个具体类型的输入输出函数

// 参数输入为number类型,通过类型判断直接知道输出也为number
function testFun1 (count: number) {
    return count * 2;
}
  1. 一个不确定类型的输入、输出函数,但是输入、输出函数类型一致

// 用泛型
function testFun2<T> (arg: T): T {
    return arg;
}
  1. async函数,返回的为Promise对象,可以使用then方法添加回调函数,Promise是一个泛型函数,T泛型变量用于确定then方法时接收的第一个回调函数的参数类型。

// 用接口
interface PResponse<T> {
    result: T,
    status: string
};

// 除了用接口外,还可以用对象
// type PResponse<T> = {
//   	result: T,
//    status: string
// };

async function testFun3(): Promise<PResponse<number>> {
    return {
        status: 'success',
        result: 10
    }
}

Ts在React中的使用到这个位置就告一段落了,欢迎各位老铁联系我共同学习、交流。

··············· 执鸢者简介 ·················

看号主详细信息,来这

瞅一瞅

d210f1a9672fc316a7f395a809fb4727.png

识别方二维码加我微信、拉你进交流

2b1c9ae26103deb59b64b4b4c81cb311.png

【1】前端百题斩系列

【2】Vue系列

【3】React系列

【4】前端基础系列

【5】基础知识

【6】浏览器系列

【7】构建工具系列

【8】网络系列

【9】Node系列

【10】源码系列

【11】前端有意思

【12】手撕算法系列

【13】个人总结

【14】杂科

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wang_yu_shun/article/details/123675804

智能推荐

BASE64、MD5、SHA、HMAC几种加密算法-程序员宅基地

文章浏览阅读106次。BASE64编码算法不算是真正的加密算法。 MD5、SHA、HMAC这三种加密算法,可谓是非可逆加密,就是不可解密的加密方法,我们称之为单向加密算法。我们通常只把他们作为加密的基础。单纯的以上三种的加密并不可靠。 BASE64 按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The ..._base 64编码 和mad5 和雪花算法

住宅IP、家庭宽带IP以及原生IP,它们有什么区别?谷歌开发者账号应选择哪种IP?-程序员宅基地

文章浏览阅读1.1k次。IP地址(Internet Protocol Address)是互联网协议地址的简称,是互联网通信的基础,互联网上每一个网络设备的唯一标识符每个在线的设备都需要一个IP地址,这样才能在网络中找到它们并进行数据交换。IP地址有很多种类型,今天跟大家简单分享一下住宅IP、家庭宽带IP以及原生IP的区别。住宅IP通常是指由互联网服务提供商(ISP)分配给家庭的或小型办公室使用的互联网连接IP地址,并可能随着网络连接的变化而变化。此类IP地址主要用于日常网络活动,如浏览网页、发送接收电子邮件、上网冲浪等。

如何更改layui form表单位置,宽度,颜色等_layui-form-item 宽度-程序员宅基地

文章浏览阅读2.6w次,点赞14次,收藏30次。如何更改layui form表单位置,宽度,颜色等_layui-form-item 宽度

【翻译】Efficient Data Loader for Fast Sampling-Based GNN Training on Large Graphs_pagraph: scaling gnn training on large graphs via -程序员宅基地

文章浏览阅读612次。写的非常好_pagraph: scaling gnn training on large graphs via computation-aware caching

炫酷的HTML代码-程序员宅基地

文章浏览阅读2.7w次,点赞61次,收藏285次。很炫酷的html代码:<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>star</title><script type="text/javascript">window.onload = function () {C = Math.cos; // cache Math objectsS = Math.si.._炫酷的html

【HDU - 1166】敌兵布阵 (线段树模板 单点更新+ 区间查询)-程序员宅基地

文章浏览阅读204次。题干:C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。 中央情报局要研究敌人究竟演习什...

随便推点

【免费题库】华为OD机试C卷 - 数字字符串组合倒序(Java 代码+解析)-程序员宅基地

文章浏览阅读2.3k次。题目描述对数字,字符,数字串,字符串,以及数字与字符串组合进行倒序排列。字符范围:由 a 到 z, A 到 Z,数字范围:由 0 到 9符号的定义:“-”作为连接符使用时作为字符串的一部分,例如“20-years”作为一个整体字符串呈现;连续出现 2 个 “-” 及以上时视为字符串间隔符,如“out--standing”中的”–“视为间隔符,是 2 个独立整体字符串”out”和”standing”;除了 1,2 里面定义的字符以外其他的所有字符,都是非法字符,作为字符串的间隔符处理,倒序后

Android(14) ArrayAdapter(数组适配器)的三种方法-程序员宅基地

文章浏览阅读5w次,点赞36次,收藏138次。ArrayAdapter数组适配器用于绑定格式单一的数据,数据源可以是集合或者数组列表视图(ListView)以垂直的形式列出需要显示的列表项。实现过程:新建适配器->添加数据源到适配器->视图加载适配器第一种:直接用ListView组件创建列表每一行只有一行文字效果如图:activity_list布局:<?xml version="1.0" e..._arrayadapter

助力商家健康经营 创业者为水滴直播点赞-程序员宅基地

文章浏览阅读43次。近日,水滴直播平台登上了舆论的风口浪尖。有人认为水滴直播涉嫌侵犯隐私,但也有人表示这种互联网新生事物可以有效规避很多风险,值得鼓励,不应一棒子打死。记者采访时发现,很多商家、创业者对于水滴直播纷纷表示支持,并直言水滴直播为他们的经营带来了很大帮助。 邹志泉在北京丰台区经营着一家批发厂家直销男女内衣裤的店铺,平时就打开水滴直播,分享他在店铺的经营画面。面对水滴直播涉及隐私的提问,邹志泉明确表...

java毕业设计宠物收养管理系统Mybatis+系统+数据库+调试部署-程序员宅基地

文章浏览阅读67次。springboot基于SpringBoot的电影社区网站。springboot基于springboot食品销售网站。ssm基于微信平台的校园汉服租赁系统的设计与实现。ssm基于SSM高校教师个人主页网站的设计与实现。ssm基于SSM框架的在线健康系统设计与实现。ssm基于HTML的武昌理工学院二手交易网站。ssm基于JavaEE的网上图书分享系统。ssm基于Javaee的项目任务跟踪系统。

Nginx使用之反向代理、负载均衡、动静分离教程。_php动静分离-程序员宅基地

文章浏览阅读61次。负载均衡是指将客户端的请求分发到多个后端服务器,以平衡服务器的负载。反向代理是指将客户端的请求转发到后端服务器,并将响应返回给客户端。通过配置反向代理,Nginx将转发所有来自客户端的请求到后端服务器,并将响应返回给客户端。通过这样的配置,Nginx将根据请求的URL路径选择是将请求转发到后端服务器还是直接返回静态资源文件。通过配置负载均衡,Nginx将按照指定的策略将客户端的请求分发到后端服务器上,从而实现负载均衡。配置反向代理:编辑Nginx配置文件(通常是nginx.conf),在。_php动静分离

HTML5有哪些新特性_谈谈html5的一些新特性-程序员宅基地

文章浏览阅读9.5k次,点赞3次,收藏18次。(一) 语义标签(二)增强型表单(三)视频和音频(四)Canvas绘图(五)SVG绘图(六)地理定位(七)拖放API(八) WebWorker(九) WebStorage(十)Web..._谈谈html5的一些新特性

推荐文章

热门文章

相关标签