react

JSXElement对象

过程:JSX经过Babel转译为createElement,createElement执行得到ReactElement对象

  • 一个ReactElement对象
const ReactElement={
	$$typeof:REACT_ELEMENT_TYPES,	// Element元素类型
	type:type,			// 是标签还是组件
	key:key,			// 有没有key
	ref:ref,			// 有没有ref
	props:props			// 组件或标签有哪些属性,哪些后代元素/子组件
	.....
}

组件

  • 类组件
export default class App extends React.Component{
rnder(){
	return<div>类组件</div>
}
}
  • 函数组件
export default function App(){
	return(
		<div>函数组件</div>
	)
}
  • 静态属性
function Form(){}
Form.Item=function(){}
<Form>
	<Form.Item></Form.Item>
</Form>

组件状态 State

  • setSate处于同步逻辑中 异步更新状态
const [username,setUserName]=useState('aaaa')
function handleClick(){
	// setUserName 处于同步逻辑中,它是异步更新状态
	setUserName('bbb')
	console.log(username) // aaaa
}
  • setState 处于异步的逻辑中 同步更新状态

  • 如果状态变更如何拿到最新状态

  1. 在类组件中
    this.setState可以接收一个回调函数,监听到状态
state={username:'husa'}
handleClick=()=>{
	// 在回调中可以拿到最新状态
	this.setState({username:'bus'},()=>{console.log('更新后的状态',this.state.username)})
}
  1. 在函数组件中
    useState没有回调函数,它没有办法感知到状态改变
    需要借助useEffect监听状态
const [username,setUserName]=useState('aaaa')
function handleClick(){
	// setUserName 处于同步逻辑中,它是异步更新状态
	setUserName('bbb')
	console.log(username) // aaaa
}
useEffect(()=>{
	console.log('获取新的状态',username) // bbb
},username)
this.setState({count:this.state.count+1},()=>console.log('更新完成'))

注意事项setState可以自动合并更新对象(传部分数据,内部自动合并),useState不会合并更新对象,在使用useState你需要传完整的数据。

state={userName:'sdd',phone:231}
setState({phone:323}) //ok
useState({phone:322}) //no
useState({...state,phone:323}) //ok 

多次执行相同的setState会多次执行更新,多次的相同的useState只更新一次

onRefrese=()=>{
   	this.setState({num:this.state.num}) // 状态并没有发生改变但仍然会重新渲染
   }

组件的通信方式

  1. propscallback 父子间通信
  2. ref
  3. Redux,Mobx状态管理
  4. context
  5. event bus 发布订阅模式
class eventBus {
	event = {}
	// 绑定事件
	on(eventName, cb) {
		if (this.event[eventName]) {
			this.event[eventName].push(cb)
		} else {
			this.event[eventName] = cb
		}
	}
	// 触发事件
	emit(eventName, ...params) {
		if (this.event[eventName]) {
			this.event[eventName].forEach((cb) => {
				cb(...params)
			})
		}
	}
	// 取消事件
	off(eventName) {
		if (this.event[eventName]) {
			delete this.event[eventName]
		}
	}
}
export default  eventBus

HOC 高阶组件

输入一个组件,输出一个新组件,可以解决代码复用和逻辑复用问题

  • 高阶组件代理属性
    包装一个组件给这个组件注入新的属性,返回一个新的组件,与cloneElement很作用类似
    给原始组件包裹一层高阶组件,以达到组件功能增强的效果
  1. 使用cloneElement
function HOC({children}){
	const newPerson=React.cloneElement(children,{email:'yourEmail'})
	return <div>{newPerson}</div>
}
function Person(props){
	console.log(props)
	return <div>Person</div>
}
export default class App extends Component {
	render() {
		return (
			<div style={styles}>
				<HOC>
					{/*  Person 只有一个name属性,要用cloneElement给它注入新属性*/}
						{/* 在Person外面包裹一层HOC */}
				<Person name='yourName'></Person>
				</HOC>
			</div>
		)
	}
}
  1. 不使用cloneElement
function HigherOrderComponent(TargetComponent){
	return class NewComponent extends Component{
		state={
			prop:'一个新属性'
		}
		render(){
			return <div><TargetComponent {...this.props} newProp={this.state.prop}/></div>
		}
	}
}
function Person(){
	return <div>Person</div>
}
// 使用高阶函数更新组件
const NewPerson=HigherOrderComponent(Person)
export default class App extends Component {
	render() {
		return (
			<div style={styles}>
				{/* 使用高阶函数去渲染一个新的组件 */}
				<NewPerson name='yourName'></NewPerson>
			</div>
		)
	}
}

hooks

useEffect()

useEffect(()=>{},[])
useEffect开始的时候会执行一次,后面每次依赖发生改变都会再次执行
useEffect在页面渲染完成后执行
useLayoutEffectdom树构建完成之后,页面渲染之前执行。也就是说useLayoutEffect可嫩会阻塞页面渲染。如果有dom操作应该放在useLayoutEffect中,可以减少重排和重绘次数。

useState() 缓存状态

useState可以缓存状态,及state更新,组件渲染,状态并不会重置。

useCallback 记忆函数

每次更新都会导致组件重新渲染,组件内部的一些局部变量都可能会被重新创建。
使用useCallback可以缓存函数,防止组件重新渲染,引发函数重新创建,提高性能
useCallback(()=>{},[])只有依赖发生改变函数才会再次被声明,如果依赖项为空,表示一直使用旧值

const [number,setNumber]=useState(0)
let num=0
const callback=()=>{
	setUser(number+1) // 每次更新,callback就会重新创建,永远都只能打印0
	console.log(num++)
}

const usecallback=useCallback(()=>{
	setUser(number+1) // 使用useCallback,组件渲染不会重新声明函数,num正常增加
	console.log(num++)
},[num])

useMemo

useCallback(fn,[]) =>useMemo(()=>fn,[]) useCallback不会执行函数,useMemo会执行函数。

useRef

useRef不仅可以获取dom还可以缓存变量

let num=useRef(0)
const handleClick=()=>{
	num.current++ // 每次执行num.current都会增加,组件更新num不会被重置
}

let number=0
const handelClick1=()=>{
	number++ // 每次执行number都会增加,但状态改变,组件更新number就会被重置
}

react-router

react-router将路径与页面进行关联

Routes

Routes指定了路由表中的组件应该在哪个位置显示
在这里插入图片描述
当我们点击link它会改变路由,Routes映射表就会查找路由对应的组件,并将它放到Routes所在的位置

Route

Route表示路由和组件的映射关系
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
<Route path="*" element={<NotFound/>}/> 其它会被映射到NotFound

export default function App() {
	return (
		<div className="app">
			<Header></Header>
			<div>
				<Routes>
					<Route path="" element={<Home />}></Route>
					<Route path="/about" element={<About />}></Route>
				</Routes>
			</div>
		</div>
	)
}
function Header() {
	return (
		<>
			<Link to={"/"}>home</Link>
			<Link to={"/about"}>about</Link>
		</>
	)
}

改变路由的方法

  1. Link to target
  2. NavLink to target
  3. Navigate to target
  4. useNavigate const navigate = useNavigate() navigate('跳转的路径',{'你要传递的信息'})
    前面是3个是声明式的方式,都有to属性改变路由,因为都是组件,所以可以向后传递属性(状态)
    最后一个是hooks命令式的方式,navigate接收的参数就是你要去的地方

接收路由信息

我们知到像Link,NavLink,Navigate这些组件,路由跳转时可以携带状态(能让我们知到到底是从哪里跳转过来的),
那么怎么接收这些状态

  • useLoaction可以获取这些状态
    在这里插入图片描述
    About组件有一个Link链接,当我们点击这个链接,就会跳转到Home组件,Home使用location就能拿到对应的信息,这样Home就知到是谁跳过来的了。
function Header() {
	return (
		<>
			<Link to={"/"} state={"我是header里面的跳转"}>
				home
			</Link>
			<Link to={"/about"}>about</Link>
		</>
	)
}
function Home() {
	const location = useLocation()
	return (
		<>
			<p>我是主页</p>
			<p>{location.state}</p>
		</>
	)
}

动态路由(any路由)

<Route path="/images/:any" element={<image />} /> 在images后面跟任何东西都会匹配到image组件
可以使用useParams拿到URL中动态变化的部分
const params=useParams()
使用params.any拿到url的参数,然后向后端发请求
在这里插入图片描述

嵌套路由

  • 第一种写法
    在这里插入图片描述
  • 第二种写法
    在这里插入图片描述
    在这里插入图片描述

跨域

  1. npm install http-proxy-middleware
  2. 配置setupProxy.js
const { createProxyMiddleware } = require("http-proxy-middleware")
module.exports = function (app) {
	app.use(
		"api",
		createProxyMiddleware({
			target: "https://xxx.com/",
			changeOrigin: true
		})
	)
}

  1. 请求数据
fetch(api/xxxxx)
.then((response) => response.json())
.then((data) => console.log(data))

注意:虽然服务器之间没有跨域限制,但别人的服务器都有防爬措施。

Redux

Flux

在这里插入图片描述

redux 工作流

在这里插入图片描述
状态由reducer修改,reducer决定每个action应该怎么去修改store
(state, action) => newState
在这里插入图片描述
视图提供actionreducer会根据action计算新的状态。
reducer相当于是状态和行为的映射表
store.dispatch(action) 方法用来更新 store 里的 state
store.getState 方法用来获取 store 里的 state

  1. 先编写reducer
  2. 创建store const store=configureStore(reducer)
  3. 更新状态
  4. 获取状态

react 项目

项目配置

  1. 配置目录别名
    在vite.config.ts中
import path from 'path'

resolve:{
    alias:{
      '@':path.resolve(__dirname,'./src')
    }
  }

在tsconfig.json中

"baseUrl": "./",
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值