base
jsx
下面代码演示在 jsx 中使用字符串、变量、调用函数、调用方法以及对象的使用。注意下面的花括号只支持表达式,并不支持语句,例如:if,switch,变量声明等等
function getName(){
return 'china';
}
// 列表循环的使用
function demoFor(){
const list = [
{id: 1001, name: 'React'},
{id: 1002, name: 'Angular'},
{id: 1003, name: 'Vue'},
]
// DOM节点也被视作变量,同理在 JSX 中要使用花括号表现出来
const h1 = <h1>这里是DOM节点变量</h1>
return (
<ul>
{list.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
{h1}
)
}
// 条件表达式
function conditionalExpress(){
const b = false
// 样式对象: 样式作为对象变量可直接赋值给DOM节点
const style = { color: 'red', fontSize: 22 }
const name = <span style={style}>演示样式对象变量</span>
return (
<div className = 'App'>
{/* 逻辑与 */}
{b && <div>应该显示了吧</div>}
{b ? <span>true时显示</span> : <span>false时显示</span>}
</div>
)
}
// 绑定事件
function handleBtn(){
alert('点击了按钮');
}
// 演示点击事件
function buttonDemo(){
return (
<div className = 'App'>
<button onClick={handleBtn}>点我显示alert</button>
</div>
)
}
// 打印事件对象e
function buttonDemo(){
const handleBtn = e => {
console.log(e)
}
return (
<div className = 'App'>
<button onClick={handleBtn}>点我显示alert</button>
</div>
)
}
// 绑定事件带参数
function btnParam(){
const eve = name => {
console.log(`input name is : ${name}`);
}
return (
<div className = 'App'>
<button onClick={ () => eve('chanchaw') }>点我显示alert</button>
</div>
)
}
// 绑定事件带参数+事件对象
function btnParam01(){
const eve = (e, name) => {
console.log(`input name is : ${name}`, e);
}
return (
<div className = 'App'>
<button onClick={ e => eve(e,'chanchaw') }>点我显示alert</button>
</div>
)
}
// useState改变对象属性的用法
function useStateDemoObj(){
const [form, setForm] = useState({
id: 1001, name: '小张'
});
const handleClick = () => {
setForm({
...form,
name: '小高'
})
}
return (
<div className = 'App'>
<p>id:{form.id}</p>
<p>name:{form.name}</p>
<button onClick={handleClick}>点击改变</button>
</div>
)
}
function App(){
const aa = 101;
const fontColor = 'blue';
return (
<div className = "App">
<p>this is React App</p>
{/* 显示硬编码的字符串 */}
<p>{'硬编码的字符串'}</p>
{/* 显示 JS 变量 */}
<p>{aa}</p>
{/* 函数调用 */}
{getName()}
{/* 方法调用 */}
<p>
今天的日期
{new Date().getDate()}
</p>
{/* 使用 js 对象 */}
<div style={{ color: fontColor }}>this is a div</div>
</div>
)
}
export default App
模块与导出
第一种方法制作的模块在使用时要具名导出
function add(){...}
function sub(){...}
export { add, sub}
# 上面的方式制作的模块,在业务组件中使用方法:
import { add, sub } from './ccUtils'
第二种方式更像调用 java 类的方法
export default {
set(key: string, val: any): void {
localStorage.setItem(key, JSON.stringify(val))
},
get(key: string): any {
const val = localStorage.getItem(key)
if (!val) return ''
try {
return JSON.parse(val)
} catch {
return val
}
},
remove(key: string): void {
localStorage.removeItem(key)
},
clear(): void {
localStorage.clear()
}
}
# 业务组件中使用方法如下:
import localStorage from '../utils/localStorage'
localStorage.set();
localStorage.get();
组件
封装
下面的 props.children 表示父组件中使用本封装组件时使用双标签样式中间插入的组件,效果类似 vue 中的 slot
export default function SearchForm(props: any){
return(
<Form className='search-form' form={props.form} layout='inline' initialValues={props.initialValues}>
{props.children}
<Form.Item>
<Space>
<Button>搜索</Button>
<Button>重置</Button>
</Space>
</Form.Item>
</Form>
)
}
组件分类mermaid
graph LR
A(组件) --> B1(类组件)
A --> B2(函数式组件)
A --> B3(公共规范)
B1 --> C11(继承Component)
B1 --> C12(必须使用render函数并返回jsx)
B1 --> C13(constructor是可选.必要的初始化)
B3 --> C31(首字母大写)
click B2 "#函数式组件最简案例"
click B1 "#类组件最简案例"
组件分类markmap
---
markmap:
colorFreezeLevel: 2
---
# markmap
## 链接
- <https://markmap.js.org/>
- [GitHub](https://github.com/markmap/markmap)
## 功能
- 链接
- **强调** ~~删除线~~ *斜体* ==高亮==
- 多行
文字
- `行内代码`
类组件最简案例
import React from 'react'
export default class App extends React.Component {
render() {
return (
<div>this is app</div>
)
}
}
函数式组件最简案例

样式

// 下面是 index.css 的全部代码
.red-btn {
color: red
}
// 先导入样式文件
import './index.css'
// 组件内的样式
function styleDemo(){
return (
<div className = 'App'>
<span className={'red-btn'}>cccc</span>
</div>
)
}
// 上面是导入外部样式
// 行内样式的使用,多单词时使用小驼峰的样式
function inlineStyle(){
const sytle01 = {
color: 'blue',
fontSize: '50px'
}
return (
<span style={sytle01}>演示行内样式</span>
)
}
受控表单绑定
概述

DOM
获取DOM
先导入
import { useRef } from 'react'

设置焦点
import { useRef } from 'react'
const inputRef = useRef(null);
inputRef.current.focus();
<input ref={inputRef}/>
组件通信
父传子
可见,父组件传递来的参数,在子组件中以对象接收
// 组件通信 - 父传子
function ChildComp(props){
return (
<div>我是子组件:{props.name}</div>
)
}
function App(){
const fatherText = '张三';
return (
<div className = 'App'>
<ChildComp name = {fatherText}/>
</div>
)
}
props 的特性看下图

父组件中引用子组件时,写在子组件内部的标签都被子组件的 props.children 属性接收

子传父

兄弟通信
子组件A将数据传递给父组件,再由父组件传递给子组件B
跨层组件通信

代码实现
import { createContext, useContext } from 'react'
const MsgContext = createContext()
// 第一层组件
function Level1Cmpt(){
return (
<div className = 'level1Cmpt'>
<h1>我是第一层组件</h1>
<Level2Cmpt />
</div>
)
}
// 第二层组件
function Level2Cmpt(){
const msg = useContext(MsgContext);
return (
<div className = 'lelvel2Cmpt'>
<span>[我是第二层组件了]</span>
{msg}
</div>
)
}
// 根组件
function App(){
const fatherText = '张三';
const rootCmptText = '我是根组件的内容,用于测试跨组件通信';
// 跨层级组件通信
return (
<div>
<MsgContext.Provider value={rootCmptText}>
<h1>我是根组件的标题</h1>
<Level1Cmpt />
</MsgContext.Provider>
</div>
)
}
React Hook
规则
- 只能在组件中或者其他自定义 hook 函数中调用(自定义hook必须以 use 开头)
- 只能在组件的顶层调用,不能嵌套在 if,for 中
useTransition

useRef

useReducer
类似 redux 的用法

useContext
用于跨层级传输数据

useState
概述

function useStateDemo(){
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count+1);
}
return (
<div className = 'App'>
<p>数字:{count}</p>
<button onClick={handleClick}>点我显示alert</button>
</div>
)
}
状态不可变

对象和数组
// 更新对象时先解构再修改
const [obj, setObj] = useState({});
const handleObj = () => {
setObj({...obj,name:'cc'})
}
// 同理,数组也要先解构再新增
const [arr, setArr] = useState([]);
const handleArr = () => {
setArr({...arr,'cc'})
}
渲染一次
下面3行代码累加数据,前端页面只会渲染一次,即在执行完函数 handleState 后才渲染一次视图,而不是每执行一行就渲染一次视图。
const [state, setState] = useState(0)
const handleState = ()=> {
setState(state+1)
setState(state+1)
setState(state+1)
}
强制渲染(手动渲染)
通过函数 flushSync 可强制渲染视图
const [state, setState] = useState(0)
const handleState = ()=> {
setState(state+1)
flushSync(() => {
setState(state+1)
})
setState(state+1)
}
useEffect
概述
组件渲染完毕后会自动执行 useEffect(生命周期函数)


组件初始渲染后执行
import { useEffect } from 'react'
function httpReq(){
const URL = 'http://17.71.0.29:8080/PADEMIS/sw/checkPallet4In'
// 实例化一个Request实例
// 第一个参数一般指资源路径
// 第二个参数可以理解为请求的配置项,包含头部信息和http请求一些关键配置(请求类型、参数...)
let requestInstance = new Request(URL, {
method: 'post',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: '{"palletCode":"A0012"}'
})
// fetch方法参数同Request实例
// 第一个参数为url或者Request实例
// 第二个参数为请求配置项
fetch(requestInstance).then(response => {
// 返回的是一个Response的实例
// 调用Response实例的序列化方法,序列化成json,返回值是一个promise
// 序列化方法有 json,text,formData,blob,arrayBuffer,redirct
let result = response.json()
result.then(res => {
console.log(res)
})
}).catch(err => console.log(err)).finally(() => console.log('网络请求执行完毕!'))
}
function useEffectCmpt(){
useEffect(() => {
httpReq()
},[])// 空数组(没有依赖)表示只会在组件渲染之后执行一次
return (
<div className = 'useEffectCmpt'>
this is app
</div>
)
}
依赖项参数
下面的 “组件更新” = 由组件状态数据更新导致组件重新渲染,即组件每次重新渲染都会执行一次

第三种情况 “特性依赖项变化” 一般为传入的状态变量,下面代码表示该子组件初始化完毕后执行一次,并且每次 state 变更都会执行一次
const [state, setState] = useState(0);
useEffect(() => {
console.log('xxx');
},[state])
组件卸载后执行
//#region 组件卸载的生命周期钩子
function UnLoadHook(){
useEffect(() => {
// 组件初始渲染后执行
const timer01 = setInterval(() => {
console.log('定时器执行中...');
}, 1000)
// 组件被卸载后执行的逻辑
return () => {
clearInterval(timer01)
}
},[])// 空数组表示只在组件初始渲染后执行一次,之后组件更新时都不会执行
return (
<span>这里是测试卸载组件时清除定时器的子组件</span>
)
}
//#endregion
function App(){
// 控制子组件显示的状态变量
const [visible, setVisible] = useState(true);
const handleVisible = () => {
setVisible(!visible)
}
return (
<div>
{ visible && <UnLoadHook />}
<button onClick={handleVisible}>显示隐藏</button>
</div>
)
}
useMemo
简单案例
组件内经常变动的数据使用该 hook 可以缓存数据,在依赖条件(数据)变动后才会更新数据。例如下面代码,billList 是父组件传递来的数据,当该数据变动后必然引起本子组件数据变化进而引起视图变化,此时使用 useMemo 在计算本组件使用到的数据同时缓存起来,当组件重新渲染时如果依赖项 billList 没有变化则不会调用下面逻辑重新计算得到 monthGroup,下面代码同时使用了 lodash 的分组函数,按照日期将数据分组。
const monthGroup = useMemo(() => {
if(!billList) return []
return _.groupBy(billList, item => formatBillDateMonthly(item.date))
},[billList])
lodash 分组后的数据类似
{'2024-07-01':[...],'2024-08-09':[...]}
联动缓存
当用户操作引起组件内状态 currentMonthList 变更时要求自动计算并缓存数据时使用 useMemo,代码如下
const [currentMonthList, setMonthList] = useState([])
const monthStatistics = useMemo(() => {
const ret = {pay: 0, income: 0, balance: 0}
if(!currentMonthList || currentMonthList.length === 0) return ret
currentMonthList.forEach(item => {
if(item.type === 'pay') ret.pay += item.money
if(item.type === 'income') ret.income += item.money
ret.balance += item.money
})
return ret
},[currentMonthList])
memo
缓存组件,类似 useMemo 用于缓存数据。
useCallback
useMemo 用来缓存数据,useCallback 用来缓存函数。即组件渲染时该函数不会被重新创建
自定义hook
自定义 hook 必须以 use 开头
//#region 自定义hook
function useHook(){
const [visible, setVisible] = useState(true);
const changeVisible = () => setVisible(!visible)
return { visible, changeVisible }
}
//#endregion
function App(){
// 自定义hook
const { visible, changeVisible } = useHook();
return (
<div>
{ visible && <UnLoadHook />}
<button onClick={ changeVisible }>显示隐藏</button>
</div>
)
}
