React+TS基础

基础知识

1. 项目的初始化

  1. 初始化项目
npx create-react-app my-app --template Typescript
  1. vite初始化
yarn create vite
React

2. JSX的命名约定

  1. 小驼峰命名
<div className="style"></div>
  1. 自定义属性
<div data-c="1"></div>

3. JSX中的模块化CSS

  1. 配置声名文件
declare module "*.css"{
    
    
    const css:{
    
    [key:string]:string};
    export default css;
}
  1. 修改命名*.module.css引入
import Appcss from './App.module.css'

(1)css类型的实现(Typescript)

  1. 安装插件依赖
yarn add typescript-plugin-css-modules -S
  1. 配置插件
//tsconfig.json
{
    
    
  "compilerOptions": {
    
    
   ...
    "plugins": [{
    
    "name": "typescript-plugin-css-modules"}]
  },
  "include": ["src"],
  "references": [{
    
     "path": "./tsconfig.node.json" }]
}
  1. 添加文件夹配置
.vscode/settings.json
{
    
    
	"typescript.tsdk": "node_modules/typescript/lib",
	"typescript.enablePromptUseWorkspaceTsdk": true
}

4. 组件的类型

  1. 函数式组件
import React from "react";
import rebot from './robot.module.css'

interface RobotProps{
 id:number,
 name:string,
 email:string
}

const Robot:React.FC<RobotProps>=({id,name,email})=>{
   return <div className={rebot.cardContainer}>
    <img src={`https://robohash.org/${id}`} alt="" />
    <h2>{name}</h2>
    <p>{email}</p>
   </div> 
}

export default Robot;
  1. 类式组件
import React from "react";
import Cartcss from "./Cart.module.css"

interface Props{
 
}

interface State{
    isOpen:boolean
}

class Cart extends React.Component<Props, State>{
 constructor(props:Props){
    super(props);
    this.state={
        isOpen:false
    }
 }   
 render(): React.ReactNode {
     return (
        <div className={Cartcss.cartContainer}>
            <button className={Cartcss.button} onClick={()=>this.setState({isOpen:!this.state.isOpen})}>购物车2(件)</button>
            <div className={Cartcss.cartDropDown}
             style={
   
   {display: this.state.isOpen ?"block":"none"}}
            >
                <ul>
                    <li>robot 1</li>
                    <li>robot 2</li>
                </ul>
            </div>
        </div>
     );
 }
}
export default Cart;

5. State和Props

  1. 简单介绍
state是组件对内的接口,props是组件对外的接口

state是组件内部传递,props是组件间的数据传递

使用setState进行修改state状态

只能在构造函数中进行初始化
  1. setState是同步还是异步
// setState是异步更新,同步执行
  <button onClick={
    
    
      ()=>{
    
    
        this.setState({
    
    count:this.state.count+1},()=>{
    
    
         // 初始值 1 点击一次

         // 异步处理的结果   
          console.log("count",this.state.count);//结果: 2
        })
         // 同步结果(生命周期并没更新)  
        console.log("count",this.state.count); // 结果:1
      }
    }>+1</button>

6. react的事件处理

(1)定义函数处理this指向问题

  1. 箭头函数实现this的指向性
// 如果react中的函数是一个无参数的函数(只要event),可以
...
class Cart extends React.Component<Props, State>{
    
    
 constructor(props:Props){
    
    
    super(props);
    this.state={
    
    
        isOpen:false
    }
 }   
 handleClick=()=>{
    
    
    this.setState({
    
    isOpen:!this.state.isOpen})
 }
 render(): React.ReactNode {
    
    
    ....
     <button className={
    
    Cartcss.button} >购物车2()</button>
 }
}
export default Cart;
  1. 函数柯里化
...
class Cart extends React.Component<Props, State>{
    
    
 constructor(props:Props){
    
    
    super(props);
    this.state={
    
    
        isOpen:false
    }
 }   
  handleClick(){
    
    
    this.setState({
    
    isOpen:!this.state.isOpen})
 }
 render(): React.ReactNode {
    
    
     return (
       ...
            <button className={
    
    Cartcss.button} onClick={
    
    ()=>this.handleClick()}>购物车2()</button>
          ...
     );
 }
}
export default Cart;

(2)event对象

  handleClick(e:React.MouseEvent<HTMLButtonElement, MouseEvent>){
    
    
    // e.target事件发生的元素
    console.log("e.target",e.target) // 点击的那部分
    // e.currentTarget事件绑定的元素
    console.log("e.currentTarget",e.currentTarget); // 绑定事件的那部分
    if((e.target as HTMLElement).nodeName==="SPAN")
        this.setState({
    
    isOpen:!this.state.isOpen})
 }

7. React的生命周期

  1. 生命周期的简单介绍
   // 组件类的构造
    constructor(props){
    
    
    super(props)
    console.log('组件将要构造');
    }
    // 组件将要挂载,可以接收props,返回值添加到state中
   static getDerivedStateFromProps(props,state){
    
    
        console.log('组件将要挂载',props,state)
        return props
    }
    // 组件将要更新,返回值会传递给下一个钩子
    getSnapshotBeforeUpdate(){
    
    
         console.log('组件将要更新');
         return '快照'
    }
    // 组件更新渲染完成,第三个参数是上个传输下来的
    componentDidUpdate(presprops,prestate,snapshotValue){
    
    
        console.log('更新渲染完成',presprops,prestate,snapshotValue);
    }
  1. 发送请求
 // 挂载
  componentDidMount(): void {
    
    
    fetch("http://jsonplaceholder.typicode.com/users").
    then(res=>res.json()).
    then(data=>this.setState({
    
    robotGallery:data}))
  }
  1. 三个阶段
Mount:     创建虚拟DOM,渲染UI
   构建:   constructor(){
    
    }
   挂载:   componentDidMount(){
    
    }
Updata:    更新虚拟DOM,重新渲染UI
   处理传递过来的值:  static getDerivedStateFromProps(props,state){
    
    return props}
   判断是否要更新:    shouldComponentUpdate(...): boolean {
    
    }
   更新:              componentDidUpdate(...) {
    
    }
Unmount:   卸载虚拟DOM,移除UI
   卸载:    componentWillUnmount() {
    
    }

函数式组件

1. hooks构子

  1. 简单的介绍
给无状态组件状态(函数式组件)

消息处理的一种方法,用来监视指定程序

函数式组件中处理副作用可以把外部代码钩进来
  1. 常用钩子
状态钩子:useState 返回值[状态,状态更新函数]
副作用钩子:useEffect
跨组件的状态传递:useContext
全局的状态管理:useReducer
回调的副作用:useCallback
返回引用对象:useRef

2. useState的基本使用

import {
    
    useState} from 'react'

interface Props{
    
    }

const App:React.FC=(props:Props)=>  {
    
    
  const [count,setCount]=useState<number>(1)

  return (
    <div>
    <span>{
    
    count}</span>
    <button onClick={
    
    ()=>setCount(count+1)}>+1</button>
  </div>
  )

}

export default App

3. useEffect的基本使用

  1. 什么是副作用
处理了与函数处理无关的事情

传入相同参数得到了不同的结果
  1. 副作用钩子的使用(相当于vue的监听器)
import {
    
    useState,useEffect} from 'react'

interface Props{
    
    }

const App:React.FC=(props:Props)=>  {
    
    
  const [count,setCount]=useState<number>(1)
   /**
   * @function 执行的函数
   * @deps 监听的参数
   * 1. 参数为空,每次都会执行包括第一次
   * 2. 参数为数组包含状态,仅仅在本状态更新时执行
   * 3. 参数为空数组,相当挂载,只会第一次执行
   */
  useEffect(()=>{
    
    
    document.title=`点击了${
      
      count}`
  },[count])

  return (
   <div>
    <span>{
    
    count}</span>
    <button onClick={
    
    ()=>setCount(count+1)}>+1</button>
   </div>
  )

}

export default App
  1. 副作用钩子发送网络请求(第二参数为空数组)
import {
    
    useState,useEffect} from 'react'

interface Props{
    
    }

const App:React.FC=(props:Props)=>  {
    
    
  const [robotGallery,setrobotGallery]=useState<Array<any>>([])

  // 开发模式("development")下,且使用了严格模式("Strict Mode")下会触发两次
  // 相当于挂载,在生成模式下只会执行一次,如果为第二参数为空就会无限循环
  useEffect(()=>{
    
    
    /* 普通的.then请求
    fetch("http://jsonplaceholder.typicode.com/users").
    then(res=>res.json()).
    then(data=>setrobotGallery(data))
    */
  
    // async和await模式 
  const fetchData=async ()=>{
    
    
    const res= await fetch("http://jsonplaceholder.typicode.com/users")
    const data= await res.json()
    setrobotGallery(data)
  }
  fetchData()
  },[])
  return (
    <div className={
    
    styles.robotList}>
    {
    
    
    robotGallery.map((item)=><Robot {
    
    ...item} key={
    
    item.id}/>)
    }
   </div>

  )

}

export default App

4. useContext的基本使用

(1)React的依赖注入

  1. 父组件中注入
// 默认context
const defaultContextValue={
    
    
  author:'qql'
}
// 上下文关系
export const appContext=React.createContext(defaultContextValue)

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    {
    
    /* 注入属性 */}
    <appContext.Provider value={
    
    defaultContextValue}>
      <App/>
    </appContext.Provider>
  </React.StrictMode>
)
  1. 子组件消费
import React from "react";
import rebot from './robot.module.css'
// 引入上下文关系消费
import {
    
    appContext} from '../../main'

const Robot:React.FC<RobotProps>=()=>{
    
    
   return <appContext.Consumer>
      {
    
    
         (value)=>    
         <p>作者:{
    
    value.author}</p>
      }
   </appContext.Consumer>
}

export default Robot;

(2)使用useContext消费

import React, {
    
     useContext } from "react";
import rebot from "./robot.module.css";
// 引入上下文关系消费
import {
    
     appContext } from "../../main";

const Robot: React.FC<RobotProps> = ({
     
      id, name, email }) => {
    
    
  const value = useContext(appContext);

  return (  
      <p>作者:{
    
    value.author}</p>
  );
};

export default Robot;

(3)使用依赖注入实现全局状态管理

  1. 定义全局状态管理组件
import React, {
    
     useState } from "react";

interface AppStateValue {
    
    
  author: string;
  shoppingCart: {
    
     items: {
    
     id: number; name: string }[] };
}
interface Props {
    
    
  children: any;
}

// 默认context
const defaultContextValue: AppStateValue = {
    
    
  author: "qql",
  shoppingCart: {
    
     items: [] },
};
// 上下文关系
export const appContext = React.createContext(defaultContextValue);
// 修改上下文
export const appSetStateContext = React.createContext<
  React.Dispatch<React.SetStateAction<AppStateValue>> | undefined
>(undefined);

const AppStateProvider: React.FC<Props> = (props) => {
    
    
  const [state, setState] = useState(defaultContextValue);
  return (
    // 注入setState
    <appContext.Provider value={
    
    state}>
      {
    
    /* 修改state */}
      <appSetStateContext.Provider value={
    
    setState}>
        {
    
    /* props.children相当默认插槽 */}
        {
    
    props.children}
      </appSetStateContext.Provider>
    </appContext.Provider>
  );
};
export default AppStateProvider;
  1. 入口组件引入状态管理
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import AppStateProvider from "./Appstate";

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    {
    
    /* 注入属性 */}
    <AppStateProvider>
      <App />
    </AppStateProvider>
  </React.StrictMode>
);

  1. 物品组件中消费和修改
import React, {
    
     useContext } from "react";
import rebot from "./robot.module.css";
// 引入上下文关系消费
import {
    
     appContext, appSetStateContext } from "../../Appstate";

interface RobotProps {
    
    
  id: number;
  name: string;
  email: string;
}

const Robot: React.FC<RobotProps> = ({
     
      id, name, email }) => {
    
    
  // 对象
  const value = useContext(appContext);
  // 函数
  const setState = useContext(appSetStateContext);
  // 加入购物车操作
  const addCart = (id: number, name: string) => {
    
    
    console.log(id, name);
    if (setState) {
    
    
      setState((state) => {
    
    
        return {
    
    
          ...state, // 不影响原来的值
          shoppingCart: {
    
    
            items: [...state.shoppingCart.items, {
    
     id, name }],
          },
        };
      });
    }
  };
  return (
    <div className={
    
    rebot.cardContainer}>
      <img src={
    
    `https://robohash.org/${
      
      id}`} alt="" />
      <h2>{
    
    name}</h2>
      <p>{
    
    email}</p>
      <p>作者:{
    
    value.author}</p>
      <button onClick={
    
    () => addCart(id, name)}>加入购物车</button>
    </div>
  );
};

export default Robot;

  1. 购物车中显示
import React from "react";
import Cartcss from "./Cart.module.css";
import {
    
     FiShoppingCart } from "react-icons/fi";
import {
    
     appContext } from "../../Appstate";

interface Props {
    
    }

interface State {
    
    
  isOpen: boolean;
}

class Cart extends React.Component<Props, State> {
    
    
  constructor(props: Props) {
    
    
    super(props);
    this.state = {
    
    
      isOpen: false,
    };
  }
  handleClick(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
    
    
    // e.target事件发生的元素
    console.log("e.target", e.target);
    // e.currentTarget事件绑定的元素
    console.log("e.currentTarget", e.currentTarget);
    if ((e.target as HTMLElement).nodeName === "SPAN")
      this.setState({
    
     isOpen: !this.state.isOpen });
  }
  render(): React.ReactNode {
    
    
    return (
      <appContext.Consumer>
        {
    
    (value) => {
    
    
          return (
            <div className={
    
    Cartcss.cartContainer}>
              <button
                className={
    
    Cartcss.button}
                onClick={
    
    (e) => this.handleClick(e)}
              >
                <FiShoppingCart />
                <span>购物车{
    
    value.shoppingCart.items.length}()</span>
              </button>
              <div
                className={
    
    Cartcss.cartDropDown}
                style={
    
    {
    
     display: this.state.isOpen ? "block" : "none" }}
              >
                <ul>
                  {
    
    value.shoppingCart.items.map((item) => {
    
    
                    return (
                      <li key={
    
    item.id}>
                        {
    
    item.id}-{
    
    item.name}
                      </li>
                    );
                  })}
                </ul>
              </div>
            </div>
          );
        }}
      </appContext.Consumer>
    );
  }
}
export default Cart;

5 .自定义Hooks

  1. 抽取添加购物车的逻辑
import {
    
     useContext } from "react";
import {
    
     appSetStateContext } from "../Appstate";

// 添加购物车操作
export const useAddToCart = () => {
    
    
    // 函数
    const setState = useContext(appSetStateContext);
    // 加入购物车操作
    const addCart = (id: number, name: string) => {
    
    
        if (setState) {
    
    
            setState((state) => {
    
    
                return {
    
    
                    ...state, // 不影响原来的值
                    shoppingCart: {
    
    
                        items: [...state.shoppingCart.items, {
    
     id, name }],
                    },
                };
            });
        }
    };

    return addCart;
}
  1. 使用hooks
import React, {
    
     useContext } from "react";
import rebot from "./robot.module.css";
// 引入上下文关系消费
import {
    
     appContext, appSetStateContext } from "../../Appstate";
// 引入hooks
import {
    
     useAddToCart } from "../../hooks";

interface RobotProps {
    
    
  id: number;
  name: string;
  email: string;
}

const Robot: React.FC<RobotProps> = ({
     
      id, name, email }) => {
    
    
  // 对象
  const value = useContext(appContext);
  // 获取hooks的值
  const addCart = useAddToCart();
  return (
    <div className={
    
    rebot.cardContainer}>
      <img src={
    
    `https://robohash.org/${
      
      id}`} alt="" />
      <h2>打折商品</h2>
      <h2>{
    
    name}</h2>
      <p>{
    
    email}</p>
      <p>作者:{
    
    value.author}</p>
      <button onClick={
    
    () => addCart(id, name)}>加入购物车</button>
    </div>
  );
};

export default Robot;

高阶组件HOC

1. 介绍HOC

const hoc=higherOrde(wrappedComponent)

高阶组件HOC就是一个返回组件的函数

通过组件嵌套的方法给子组件添加更多的功能

接收组件作为参数并返回一个经过改造的新组件

两组件有相同的方法,将方法逻辑封装到HOC

2. HOC组件的简单应用

  1. 封装添加购物车的方法
import {
    
     useContext } from "react";
import {
    
     appSetStateContext } from "../../Appstate";
import type {
    
     RobotProps } from "./Robot";

export const withAddToCart = (
  ChildComponent: React.ComponentType<RobotProps>
) => {
    
    
  return (props: RobotProps) => {
    
    
    // 函数
    const setState = useContext(appSetStateContext);
    // 加入购物车操作
    const addCart = (id: number, name: string) => {
    
    
      if (setState) {
    
    
        setState((state) => {
    
    
          return {
    
    
            ...state, // 不影响原来的值
            shoppingCart: {
    
    
              items: [...state.shoppingCart.items, {
    
     id, name }],
            },
          };
        });
      }
    };
      
    return <ChildComponent {
    
    ...props} addCart={
    
    addCart} />;
  };
};

  1. 使用HOC组件
import React, {
    
     useContext } from "react";
import rebot from "./robot.module.css";
// 引入上下文关系消费
import {
    
     appContext, appSetStateContext } from "../../Appstate";
// 引入高阶组件HOC
import {
    
     withAddToCart } from "./AddToCart";

export interface RobotProps {
    
    
  id: number;
  name: string;
  email: string;
  addCart: (id: number, name: string) => void;
}

const Robot: React.FC<RobotProps> = ({
     
      id, name, email, addCart }) => {
    
    
  // 对象
  const value = useContext(appContext);
  return (
    <div className={
    
    rebot.cardContainer}>
      <img src={
    
    `https://robohash.org/${
      
      id}`} alt="" />
      <h2>{
    
    name}</h2>
      <p>{
    
    email}</p>
      <p>作者:{
    
    value.author}</p>
      <button onClick={
    
    () => addCart(id, name)}>加入购物车</button>
    </div>
  );
};

export default withAddToCart(Robot);

组件之间的通讯

1. props父传子

  1. 子组件
import React from "react";

interface Props {
    
    
  title: string;
}

export const A: React.FC<Props> = (props) => {
    
    
  return <div>{
    
    props.title}</div>;
};
// 默认参数
A.defaultProps = {
    
     title: '你好' }
  1. 父组件
import {
    
     A } from "./A";

function App() {
    
    
  return (
    <A title={
    
    "我的值来自父组件"} />
  );
}

export default App;

2. props子传父(父向子传递一个函数)

  1. 子组件
import React from "react";

interface Props {
    
    
  getChildProps: Function;
}

export const A: React.FC<Props> = (props) => {
    
    
  return (
    <div>
      <button onClick={
    
    () => props.getChildProps(10)}>子传父</button>
    </div>
  );
};
  1. 父组件
import {
    
     A } from "./A";
import {
    
     useState } from "react";

function App() {
    
    
  const [count, setCount] = useState(0);
  // 接收子组件传递的参数
  const getChildProps = (value: any) => {
    
    
    setCount(value);
  };
  return (
    <>
      <A getChildProps={
    
    getChildProps} />
      <div>{
    
    count}</div>
    </>
  );
}

export default App;

3. props插槽(props传递一个jsx)

(1)默认插槽(无需传)

  1. 父组件
import {
    
     A } from "./A";

function App() {
    
    
  return (
    // 没有通过props传递,默认用children接收
    <A>
      <span>默认插槽</span>
    </A>
  );
}

export default App;
  1. 子组件
import React from "react";

interface Props {
    
    
  children: JSX.Element;
}

export const A: React.FC<Props> = (props) => {
    
    
  return <div>{
    
    props.children}</div>;
};

(2)具名插槽(props传)

  1. 父组件
import {
    
     A } from "./A";

function App() {
    
    
  return (
    <A title={
    
    <span>具名插槽</span>}></A>
  );
}

export default App;
  1. 子组件
import React from "react";

interface Props {
    
    
  title: JSX.Element;
}

export const A: React.FC<Props> = (props) => {
    
    
  return <div>{
    
    props.title}</div>;
};

4. 跨级传输

(1)简单的使用

  1. 父组件
import {
    
     A } from "./A";
import React from "react";

// 默认context
const defaultContextValue = {
    
    
  title: "",
};
// 上下文关系
export const appContext = React.createContext(defaultContextValue);

function App() {
    
    
  defaultContextValue.title = "跨级传输";
  return (
    <appContext.Provider value={
    
    defaultContextValue}>
      <A></A>
    </appContext.Provider>
  );
}

export default App;
  1. 子(后代)组件
import React, {
    
     useContext } from "react";
import {
    
     appContext } from "./App";

interface Props {
    
    }

export const A: React.FC<Props> = (props) => {
    
    
  //第一种方法:使用useContext钩子
  const res = useContext(appContext);
  return (
    // 第二种方法:使用appContext.Consumer组件
    <appContext.Consumer>
      {
    
    (value) => (
        <div>
          {
    
    value.title}-{
    
    res.title}
        </div>
      )}
    </appContext.Consumer>
  );
};

(2)模块化传输

  1. 传输模块
import React from "react";

interface Props<T> {
    
    
  children: any;
  value: T;
}

// 上下文关系
export const appContext: React.Context<{
    
     title: string } | {
    
    }> =
  React.createContext({
    
    });

export const ProviderConsumer: React.FC<Props<{
    
     title: string }>> = (props) => {
    
    
  return (
    <appContext.Provider value={
    
    props.value}>
      {
    
    props.children}
    </appContext.Provider>
  );
};

  1. 父组件
import {
    
     A } from "./A";
import {
    
     ProviderConsumer } from "./ProviderConsumer";

function App() {
    
    
  return (
    <ProviderConsumer value={
    
    {
    
     title: "夸级传输" }}>
      <A></A>
    </ProviderConsumer>
  );
}

export default App;

  1. 子(后代)组件
import React, {
    
     useContext } from "react";
import {
    
     appContext } from "./ProviderConsumer";

interface Props {
    
    }

export const A: React.FC<Props> = (props) => {
    
    
  const value = useContext(appContext) as any;
  return <div>{
    
    value.title}</div>;
};

猜你喜欢

转载自blog.csdn.net/qq_45897636/article/details/127622184