npx create-react-app tsui
cd tsui
yarn start
//React负责逻辑控制,数据 -> VDOM
import React from "react";
//ReactDom渲染实际DOM,VDOM -> DOM
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
// React JSX => React.createElement(...)
// babel-loader把JSX 编译成相应的 JS 对象,
// React.createElement再把这个JS对象构造成React需要的虚拟dom。
ReactDOM.render(<App />, document.getElementById("root"));
serviceWorker.unregister();
# jsx在react中
- for循环用可以在jsx中使用arr.map代替,(注意 forEach,则不会返回数据 )
- 过滤部分数据array.filter
- if else 语句可以使用三目运算符代替
- 函数调用可以直接写在jsx表达式中
- if 判断的话可以依赖 && 运算符实现
- 模块化module用来实现css不会相互干扰
- CSS属性:静态值用双引号,动态值用花括号;class => className 、 for => htmlFor 等要特殊处理。
- 需要最外层添加包裹标签,可以是
<></>,JSX 虽然看起来很像 HTML,但在底层其实被转化为了 JavaScript 对象,你不能在一个函数中返回多个对象,除非用一个数组把他们包装起来。这就是为什么多个 JSX 标签必须要用一个父元素或者 Fragment 来包裹。
import React from "react";
import ReactDOM from "react-dom";
// import "./index.css";
import styles from "./index.module.css";
import logo from "./logo192.png";
const name = "React";
const obj = {
fistName: "Harry",
lastName: "Potter"
};
function formatName(name) {
return name.fistName + " " + name.lastName;
}
const greet = <div>good</div>;
const show = true;
const a = [0, 1, 2];
const jsx = (
<div className={styles.app}>
<div>hello, {name}</div>
<div>{formatName(obj)}</div>
{greet}
{show ? greet : "登录"}
{show && greet}
<ul>
{/* diff时候,首先比较type,然后是key,所以同级同类型元素,key值必须得 唯一 */}
{a.map(item => (
<li key={item}>{item}</li>
))}
</ul>
<img
src={logo}
// className="logo"
className={styles.logo}
style={{ width: "50px", height: "30px" }}
/>
</div>
);
ReactDOM.render(jsx, document.getElementById("root"));
//基本使用 表达式用{}包裹
//函数
//JSX对象
//条件语句
//数组
//属性
//模块化
# react constructor的使用
constructor 是类通用的构造函数,常用于初始化。所以在过去,constructor 通常用于初始化 state 与绑定函数。
import React from 'react'
class Counter extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0,
}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
// do some stuff
}
render() {
return null
}
}
当类属性开始流行之后,React 社区的写法发生了变化,即去除了 constructor。
import React from 'react'
class Counter extends React.Component {
state = {
count: 0,
}
// 类属性第三阶段提案
handleClick = () => {
// do some stuff
}
render() {
return null
}
社区中去除 constructor 的原因非常明确:
- constructor 中并不推荐去处理初始化以外的逻辑;
- 本身 constructor 并不属于 React 的生命周期,它只是 Class 的初始化函数;
- 移除 constructor,代码也会变得更为简洁。
# react路由表写法
import { BrowserRouter,HashRouter } from "react-router-dom";
import Router from "@/routers/index";
function App() {
return (
<HashRouter>
<Router />
</HashRouter>
)
}
export default App
import { Navigate, useRoutes } from 'react-router-dom'
import LayoutCustom from '@/layouts/index'
import Login from '@/views/login/index'
import DigitalTwin from '@/views/digitalTwin/index'
import ProjectManage from '@/views/projectManage/index'
export interface MetaProps {
keepAlive?: boolean
requiresAuth?: boolean
title: string
key?: string
}
export interface RouteObject {
caseSensitive?: boolean
children?: RouteObject[]
element?: React.ReactNode
path?: string
meta?: MetaProps
isLink?: string
}
export const rootRouter: RouteObject[] = [
{
path: '/',
element: <Navigate to="/login" />,
},
{
path: '/login',
element: <Login />,
meta: {
requiresAuth: false,
title: '登录页',
key: 'login',
},
},
{
element: <LayoutCustom />,
children: [
{
path: '/digital/index',
element: <DigitalTwin />,
meta: {
requiresAuth: true,
title: 'home',
key: 'digital',
},
},
],
},
{
element: <LayoutCustom />,
children: [
{
path: '/project/scene/:ID/:Name',
element: <ProjectManage />,
meta: {
requiresAuth: true,
title: '项目管理',
key: 'digital',
},
},
],
}
]
const Router = () => {
const routes = useRoutes(rootRouter)
return routes
}
export default Router
# useRoutes
useRoutes是一个React的钩子(Hook),它允许您在函数组件中使用路由。它是React Router v6中引入的新功能,用于替代传统的React Router v5中的
# outlet子路由渲染
在 react-router-dom 中,Outlet 是一个用于渲染子路由的组件。当用户导航到一个子路由时,Outlet 会渲染对应的子路由组件。
import { Outlet } from "react-router-dom";
import { Layout } from "antd";
import LayoutHeader from "./components/Header";
import SiderMenu from "./components/SiderMenu";
import "./index.scss";
const LayoutCustom = () => {
const { Content } = Layout;
return (
<section className="container">
<LayoutHeader></LayoutHeader>
<Layout>
<SiderMenu></SiderMenu>
<Content>
<Outlet></Outlet>
</Content>
</Layout>
</section>
);
};
export default LayoutCustom;
# reactdom
自 React v0.14 开始,官方将与 DOM 相关的操作从 React 中剥离,组成单独的 react-dom库,从而让 React 能兼容更多的终端。在引入 react-dom 库后,就能调用一个全局对象:ReactDOM。
ReactDOM只包含了unmountComponentAtNode()、findDOMNode()、createPortal()和render()等为数不多的几个方法。
findDOMNode():当组件被渲染到页面真实的 DOM 中后,就能通过 findDOMNode()方法得到生成的 DOM 元素,然后就能完成诸如读值和计算尺寸等操作。注意,findDOMNode()只能获取已挂载的组件,并且不能用于函数组件。在组件的生命周期中,它只能存在于 componentDidMount()和 componentDidUpdate()两个回调函数中,在其他地方调用会抛出一个错误,具体如下所示。(官方不推荐使用,未来版本移除)
class Btn extends React.Component {
render() {
ReactDOM.findDOMNode(this); //抛出错误
return <button>提交</button>;
}
componentDidMount() {
ReactDOM.findDOMNode(this); //<button>提交</button>
}
}
在上面的示例中,this 指向的是 Btn 组件实例,在将 this 传给 findDOMNode()方法后,得到了一个<button>元素。有一点要注意,如果组件中的 render()返回 null 或 false,那么findDOMNode()只会返回 null。
- createPortal():在 React v16 中,新增了 Portal 特性,能让组件渲染到父组件以外的DOM 节点中。这个特性适用于需要跳出容器的场景,例如,创建页面内定制的弹框。在 React 中使用 Portal 特性,需要调用 ReactDOM 上的一个新方法:createPortal()。此方法能接收两个参数,第一个参数是可渲染的 React 子元素,例如,字符串或 React 元素数组等;第二个参数是 DOM 元素,也就是要挂载的容器。关于这个方法的具体使用可参考下面的示例。
class Btn extends React.Component {
render() {
return ReactDOM.createPortal(this.props.children, document.body);
}
}
ReactDOM.render(<Btn><p>按钮</p></Btn>, document.getElementById("container"));
unmountComponentAtNode:此 API 将在未来的 React 主要版本中被移除。在 React 18, unmountComponentAtNode 已被 root.unmount() 取代.
unmountComponentAtNode 用于从 DOM 中移除一个已挂载的 React 组件。
unmountComponentAtNode(domNode)
# 常见插件
- Formik 是一个用于 React 的小型表单库,提供了验证、跟踪表单状态和处理表单提交等功能,让表单的测试和重构变得轻而易举。
- Relay 是一个用于 React 的 GraphQL 客户端框架,它提供了一种声明式方式来处理数据,并自动管理缓存和数据更新。
- immer或者其他use-immer类库.方便修改setState生成的对象只想改很少的部分。
react基础1 →