【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;
相关推荐
来自星星的坤3 小时前
Vue 3中如何封装API请求:提升开发效率的最佳实践
前端·javascript·vue.js
vvilkim4 小时前
全面解析React内存泄漏:原因、解决方案与最佳实践
前端·javascript·react.js
vvilkim4 小时前
React批处理(Batching)更新机制深度解析
前端·javascript·react.js
Bayi·4 小时前
前端面试场景题
开发语言·前端·javascript
程序猿熊跃晖5 小时前
Vue中如何优雅地处理 `<el-dialog>` 的关闭事件
前端·javascript·vue.js
进取星辰5 小时前
12、高阶组件:魔法增幅器——React 19 HOC模式
前端·javascript·react.js
拉不动的猪5 小时前
前端低代码开发
前端·javascript·面试
程序员张35 小时前
Vue3集成sass
前端·css·sass
夜跑者5 小时前
axios 在请求拦截器中设置Content-Type无效问题
前端
知识分享小能手5 小时前
JavaScript学习教程,从入门到精通,Ajax与Node.js Web服务器开发全面指南(24)
开发语言·前端·javascript·学习·ajax·node.js·html5