【React+ts】 react项目中引入bootstrap、ts中的接口

一、在react项目中引入bootstrap

这个直接用npm下载包然后在index.js中引入就可以了。

bash 复制代码
npm install bootstrap react-bootstrap

后面那个必须要下载,应该有什么联动的包要用。

然后在index.tsx中引入

typescript 复制代码
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/js/bootstrap";

二、ts中的interface接口

2.1 对象类型接口

ts中的interface是用来描述对象或函数的。是一种代码协作必须遵守的契约。我的理解就是规范里面的数据,比如说,在实例化的时候哪些东西必须要,哪些东西可以不要,以及哪些东西可以任意类型。

里面的数据可以定义以下几种类型。

  1. 确定类型:必须要有的数据。
  2. 可选属性:可以没有的属性。
  3. 任意属性:说明属性类型可以更改,名字可定义。
  4. 只读属性:实例化后不可更改。
typescript 复制代码
interface Person {
    age: number,           // 确定属性
    name?: string,         // 可选属性(加问号即可)
    [propName: string]: any, // 任意属性
    readonly sex: string,  // 只读属性
}

2.2 函数类型接口

列出参数列表和返回值类型的定义。

typescript 复制代码
// 函数类型接口
interface Func {
    // 定义接收两个必选 number 类型参数,和一个可选字符串参数 desc,该函数返回 number 类型
    (x: number, y: number, desc?: string): number
}

三、react中定义组件的方式

有两种定义组件方式,一种是函数式组件,一种是类式组件。

3.1函数式组件

typescript 复制代码
//基本定义方式
import React from "react";
 
export default function Discovery() {
  return <div>发现页</div>;
}

//组件传参数
import React from "react";
 
export default function Discovery(props: any) {
  console.log(props);
  return <div>{props.text}</div>;
}


//类型定义,说明是个函数式组件也可以简写FC
import React, { memo } from "react";
Import type {FunctionComponent} from "react";
 
const Discovery: FunctionComponent<any> = (props) => {
  console.log(props);
  return <div>{props.text}</div>;
};

//memo函数的作用是判断组件是否发生变化,如果没有发生变化则不重新渲染
export default memo(Discovery);

3.2 类式组件

typescript 复制代码
//基本定义方式
import React, { Component } from "react";
 
class Discovery extends Component {
  render() {
    return <div>发现页</div>;
  }
}
 
export default Discovery;

//类式组件传参
import React, { Component } from "react";
//这里两个any定义的一个是props type,一个是state type
 
class Discovery extends Component<any, any> {  
  constructor(props: any) {
    super(props);
    console.log(props);
    this.state = { text: props.text };
  }
  render() {
    return <div>{this.props.text}</div>;
  }
}
export default Discovery;

3.3interface与类式组件的互动

ReactNode和ReactElement 与 children属性

这里的ReactNode包含了ReactElement,如下图所示。

InterfaceTest.tsx

typescript 复制代码
import React, { ReactNode } from "react";
 
interface Iprops {
  name: string;
  age: number;
  children: ReactNode;
  height?: number;
}
 
export default function InterfaceTest(props: Iprops) {
  return (
    <div>
      <div>name:{props.name}</div>
      <div>age:{props.age}</div>
      {/* 三目运算符来条件渲染 */}
      {props.height ? <div>height:{props.height}</div> : null}
      <div>{props.children}</div>
    </div>
  );
}

Discovery.tsx

typescript 复制代码
import React, { Component } from "react";
import InterfaceTest from "./InterfaceTest";
class Discovery extends Component<any, any> {
  constructor(props: any) {
    super(props);
    console.log(props);
    this.state = { text: props.text };
  }
 
  render() {
    return (
      <div>
        {this.props.text}
        <InterfaceTest name="Carling" age={21} height={187}>
          <div>这里是子元素</div>
        </InterfaceTest>
      </div>
    );
  }
}
 
export default Discovery;

3.4代码中遇到的问题

(1)如果是类组件,子组件是否重新渲染由props和state决定;如果子组件是函数式组件,那么只要父组件渲染,子组件就会无条件进行渲染。

answer:使用memo函数对组件进行包裹。这个方法只能解决子组件属性不是函数时的情况,如果子组件是函数,则需要使用useCallback进行包裹。

这个问题出现的原因是因为,函数式组件每次重新渲染时,都会把函数体里的所有代码执行一遍。

useCallback函数

typescript 复制代码
let newFunction = useCallback(oldFunction,[dependentValue])

我的理解是只有当后面的依赖值发生变化时,前面的函数才会被运行。否则返回一样的值。

因此如果传的是空数组则oldFunction只会被定义一次。

typescript 复制代码
export default () => {
    console.log("父组件");
    const [count, setCount] = useState(1);

    let changeCount = () => {
        setCount(count + 1);
    }

    let increment = useCallback(()=>{
        console.log("increment");
    },[]) // 该函数永远不会重新定义(没有依赖)
    
    return (
        <>
            <h1>useCallback</h1>
            <p>{count}</p>
            <input type="button" value="修改count" onClick={changeCount} />
            <hr/>
            <SonFn onMyClick={increment} />
        </>
    )
}

四、组件的懒加载--webpack中的分包处理,性能优化问题--哪个需要查看下载哪个。

这个的原理就是将所有组件拆分,不放在一个文件里,哪个需要被加载去服务器下载哪个文件。

这里使用的是react库中的lazy函数,用来引入组件。

路由表定义:

typescript 复制代码
import React, { lazy } from "react";
import { Navigate } from "react-router-dom";
 
//懒加载定义
const Discovery = lazy(() => import("../components/Discovery"));
const My = lazy(() => import("../components/My"));
const Follow = lazy(() => import("../components/Follow"));
const Mall = lazy(() => import("../components/Mall"));
const Musician = lazy(() => import("../components/Musician"));
const Recommended = lazy(() => import("../components/Recommended"));
const Download = lazy(() => import("../components/Download"));
 
const routes: any[] = [
  {
    path: "/discovery",
    element: <Discovery text="发现页" />,
  },
  {
    path: "/my",
    element: <My />,
  },
  {
    path: "follow",
    element: <Follow />,
  },
  {
    path: "mall",
    element: <Mall />,
  },
  {
    path: "musician",
    element: <Musician />,
  },
  {
    path: "recommended",
    element: <Recommended />,
  },
  {
    path: "download",
    element: <Download />,
  },
  {
    path: "/",
    element: <Navigate to="/discovery" />,
  },
];
export default routes;

使用路由表的时候要用Suspense组件进行包裹,Suspense组件是通过捕获异常来进行实现的,没看之前猜测是,捕获到异常就暂停该组件的渲染,等到完成再渲染。

工作原理:

使用React的Fiber架构进行实现。Fiber架构允许React将渲染工作拆分为一个个可中断的任务单元。当遇到需要暂停的操作时,Fiber可暂停当前任务,并显示fallback---Suspense组件中定义的在等待时渲染的过渡组件。

  1. 当组件抛出异常时,React标记该Fiber节点为"suspended"状态
  2. 触发重新渲染,一旦该Promise完成,React会尝试重新渲染组件。
  3. 等待Promise完成的期间会渲染fallback。
    用Suspense组件将所有懒加载的组件全包裹了就可以。
typescript 复制代码
import React, { Suspense } from "react";
import routes from "./router/index";
import { NavLink, useRoutes } from "react-router-dom";
 
function App() {
  const element = useRoutes(routes);
  return (
    <div className="App">
      <nav className="navbar navbar-dark bg-primary">
        <div className="container-fluid">
          <NavLink className="navbar-brand" to="/discovery">
            发现音乐
          </NavLink>
          <NavLink className="navbar-brand" to="/my">
            我的音乐
          </NavLink>
          <NavLink className="navbar-brand" to="/follow">
            关注
          </NavLink>
          <NavLink className="navbar-brand" to="/mall">
            商城
          </NavLink>
          <NavLink className="navbar-brand" to="/musician">
            音乐人
          </NavLink>
          <NavLink className="navbar-brand" to="/recommended">
            云推歌
          </NavLink>
          <NavLink className="navbar-brand" to="/download">
            下载客户端
          </NavLink>
        </div>
      </nav>
      <Suspense fallback="loading...">
        {element}
      </Suspense>
    </div>
  );
}
 
export default App;
相关推荐
gongzemin3 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox15 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
树上有只程序猿43 分钟前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼1 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
黄毛火烧雪下1 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞2 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行2 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_593758102 小时前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox
掘金一周2 小时前
金石焕新程 >> 瓜分万元现金大奖征文活动即将回归 | 掘金一周 4.3
前端·人工智能·后端