赞
踩
URL
发生改变时,页面的显示结果可以根据URL
的变化而变化,但是页面不会刷新react-router
主要分成了几个不同的包(这一块先不写了)Route
用于路径的匹配,然后进行组件的渲染Link
组件 NavLink
是在Link
基础之上增加了一些样式属性,例如组件被选中时,发生样式变化 ( activeStyle , activeClassName )swich
组件的作用适用于当匹配到第一个组件的时候,后面的组件就不应该继续匹配组件挂载时
当组件实例被创建并插入DOM时,其生命周期调用顺序如下:
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
组件更新时
当组件的props或state发生变化时会触发更新。组件更新的生命周期调用顺序如下:
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
组件卸载时
当组件从DOM中移除时会调用如下方法
componentWillUnmount()
React 新的生命周期方法主要是为了支持 Fiber 架构中的三个新概念而设计的: fiber节点,异步渲染,可中断性
getDerivedStateFromProps(静态方法) 取代了componentWillMount和 componentWillReceiveProps
getSnapshotBeforeUpdate 取代了componentWillUpdate
getDerivedStateFromProps 中禁止了组件去访问 this.props, 由于 this.props
可能在任何时刻发生变化,所以计算出来的 state 对象可能会与旧的 state 对象相同,从而导致状态更新无效和不必要的组件重新渲染。 在 getDerivedStateFromProps
方法中应该始终使用参数中的 nextProps
,而不是 this.props
。这样可以保证组件状态的计算是基于最新的 props,从而避免了状态更新无效和渲染性能的问题。
getSnapshotBeforeUpdate 方法是在组件的 render
方法被调用后,在更新 DOM 之前被调用的 ,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素信息
是可以保证与componentDidUpdate 中一致的。
在 React 16 之前,VirtualDOM 的更新采用的是Stack架构
实现的,也就是循环递归方式。不过,这种对比方式有明显的缺陷,就是一旦任务开始进行就无法中断,如果遇到应用中组件数量比较庞大,那么VirtualDOM 的层级就会比较深,带来的结果就是主线程被长期占用,进而阻塞渲染、造成卡顿现象。
fiber
:为了避免出现卡顿等问题,我们必须保障在执行更新操作时计算时不能超过16ms
,如果超过16ms,就需要先暂停,让给浏览器进行渲染,后续再继续执行更新计算。而Fiber架构就是为了支持“可中断渲染
”而创建的。 解决了react在渲染大量dom节点出现丢帧的问题
React Fiber 与浏览器的交互流程如下图。
数据结构
,是fiber树结构的节点单位,react16新架构下的虚拟dom在 Fiber 架构中,React 将组件的更新过程分为两个阶段:reconciliation 和 commit。其中 reconciliation 阶段主要负责计算出更新后的 Virtual DOM 树,并确定哪些组件需要进行重新渲染,而 commit 阶段则负责将 Virtual DOM 树的变化映射到真实的 DOM 上。
总结:相比传统的Stack架构,Fiber 将工作划分为多个工作单元,每个工作单元在执行完成后依据剩余时间决定是否让出控制权给浏览器执行渲染。 并且它设置每个工作单元的优先级,暂停、重用和中止工作单元。 每个Fiber节点都是fiber tree上的一个节点,通过子、兄弟和返回引用连接,形成一个完整的fiber tree。
id = root
的DOM元素中(网上很多说是在document
中,17
版本不是了);id = root
的DOM元素中触发;React
自身实现了一套事件冒泡捕获机制;React
实现了合成事件SyntheticEvent
;React
在17
版本不再使用事件池了(网上很多说使用了对象池来管理合成事件对象的创建销毁,那是16
版本及之前);id = root
的DOM元素中委托,其实是一直在触发的,只是没有绑定对应的回调函数;props
的方式,向子组件进行通讯。props
+回调的方式,父组件向子组件传递props
进行通讯,此props
为作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到⽗组件的作⽤域中。Context
设计⽬的是为了共享那些对于⼀个context
提供了组件之间通讯的一种方式,可以共享数据,其他数据都能读取对应的数据Context
通信再适合不过。event
模块进⾏通信。Redux
或者Mobx
等全局状态管理⼯具进⾏通信,这种⼯具会维护⼀个全局状态中⼼Store
,并根据不同的事件产⽣新的状态。HTML
结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程node server
接收客户端请求,得到当前的请求url
路径,然后在已有的路由表内查找到对应的组件,拿到需要请求的数据,将数据作为 props
、context
或者store
形式传入组件react
内置的服务端渲染方法 renderToString()
把组件渲染为 html
字符串在把最终的 html
进行输出前需要将数据注入到浏览器端html
节点,整个流程结束React
提供统一的事件对象,抹平了浏览器的兼容性差异React
通过顶层监听的形式,通过事件委托的方式来统一管理所有的事件,可以在事件上区分事件优先级,优化用户体验。React在合成事件上对于
16版本和
17`版本的合成事件有很大不同16
版本先执行原生事件,当冒泡到document
时,统一执行合成事件,17
版本在原生事件执行前先执行合成事件捕获阶段,原生事件执行完毕执行冒泡阶段的合成事件,通过根节点来管理所有的事件,原生的阻止事件流会阻断合成事件的执行,合成事件阻止后也会影响到后续的原生执行目的是为了防止 XSS 攻击
。因为 Synbol
无法被序列化,所以 React
可以通过有没有 $$typeof
属性来断出当前的 element
对象是从数据库来的还是自己生成的。如果没有 $$typeof
这个属性,react
会拒绝处理该元素。
effect function
应该返回一个销毁函数(return
返回的 cleanup
函数),如果 useEffect
第一个参数传入 async
,返回值则变成了 Promise
,会导致 react
在调用销毁函数的时候报错async...await
的方式),然后执行该函数。使用纯组件 – 纯组件是指那些不依赖于外部状态或引用的组件
shouldComponentUpdate 优化
不要使用内联函数定义(如果我们使用内联函数,则每次调用“render
”函数时都会创建一个新的函数实例)
function MyButton(props) {
return (
<button onClick={() => console.log('Button clicked!')}>
{props.label}
</button>
);
}
避免使用内联样式属性;
使用 immutable 不可变数据,在我们项目中使用引用类型时,为了避免对原始数据的影响,一般建议使用 shallowCopy 和 deepCopy 对数据进行处理,但是这样会造成 CPU 和 内存的浪费,所以推荐使用 immutable
给子组件设置一个唯一的 key,因为在 diff 算法中,会用 key 作为唯一标识优化渲染
使用 React.memo
进行组件记忆(React.memo
是一个高阶组件),对 于相同的输入,不重复执行;
在函数组件中使用useCallback
和useMemo
来进行组件优化,依赖没有变化的话,不重复执行
路由懒加载
原理:
在类组件中render
函数指的就是render
方法;而在函数组件中,指的就是整个函数组件
render
函数中的jsx
语句会被编译成我们熟悉的js代码,在render
过程中,react
将新调用的render
函数返回的树与旧版本的树进行比较,这一步是决定如何更新 DOM 的必要步骤,然后进行 diff
比较,更新dom树
触发机:
类组件调用 setState
修改状态
函数组件通过useState hook
修改状态
一旦执行了setState
就会执行render
方法,useState
会判断当前值有无发生改变确定是否执行render
方法,一旦父组件发生渲染,子组件也会渲染
Hooks是React 16.8版本引入的新特性,它为函数组件添加了一些类似于类组件中的状态和生命周期方法的功能
getDerivedStateFromProps
容易编写反模式代码,使受控组件和非受控组件区分模糊componentWillMount
在 React
中已被标记弃用,不推荐使用,主要的原因是因为新的异步架构会导致它被多次调用,所以网络请求以及事件绑定应该放到 componentDidMount
中componentWillReceiveProps
同样也被标记弃用,被 getDerivedStateFromProps
所取代,主要原因是性能问题。shouldComponentUpdate
通过返回 true
或者 false
来确定是否需要触发新的渲染。主要用于性能优化。componentWillUpdate
同样是由于新的异步渲染机制,而被标记废弃,不推荐使用,原先的逻辑可结合 getSnapshotBeforeUpdate
与 componentDidUpdate
改造使用。componentWillUnmount
函数中忘记解除事件绑定,取消定时器等清理操作,容易引发 bug
。Diff
算法是虚拟DOM
的一个必然结果,它是通过新旧DOM
的对比,将在不更新页面的情况下,将需要内容局部更新Diff
算法遵循深度优先,同层比较的原则react
中diff
算法主要遵循三个层级的策略:key
作为标识,通过key知道节点的变化,移动旧集合节点位置,更新为新集合节点位置setState
函数之后,React
会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation
)。React
会以相对高效的方式根据新的状态构建 React
元素树并且着手重新渲染整个 UI 界面;React
得到元素树之后,React
会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染;React
能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。state
中,由store
来管理state
。reducer
的作用是 返回一个新的state
去更新store
中对用的state
。redux
的原则,UI层
每一次状态的改变都应通过action
去触发,action
传入对应的reducer
中,reducer
返回一个新的state
更新store
中存放的state
,这样就完成了一次状态的更新subscribe
是为store
订阅监听函数,这些订阅后的监听函数是在每一次dipatch
发起后依次执行dispatch
进行重写createStore
创建仓库,接受reducer
作为参数bindActionCreator
绑定store.dispatch
和action
的关系combineReducers
合并多个reducers
applyMiddleware
洋葱模型的中间件,介于dispatch
和action
之间,重写dispatch
compose
整合多个中间件Redux
中,中间件就是放在就是在dispatch
过程,在分发action
进行拦截处理, 其本质上一个函数,对store.dispatch
方法进行了改造,在发出 Action
和执行 Reducer
这两步之间,添加了其他功能
实现原理:
applyMiddlewares
的源码 中我们可以看到 ,所有中间件被放进了一个数组chain
,然后嵌套执行,最后执行store.dispatch
。可以看到,中间件内部(middlewareAPI
)可以拿到getState
和dispatch
这两个方法常用中间件:
redux-thunk
:用于异步操作redux-logger
:用于日志记录不同点:
props是只读的,只能由父组件传递给子组件,而不能在子组件中修改。而state是可变的,在组件内部可以通过setState方法来修改其值
相同点:
1.props和state都会触发渲染更新
2.props和state都是纯JS对象(用typeof来判断,结果都是object)
shouldComponentUpdate () 可以理解为是否触发渲染的阀门,当状态发生改变时会走到该生命周期,shouldComponentUpdate接收两个参数props,state分别是更新前和更新后的状态,可以判断前后是否发生改变返回true和false,来决定是否往下执行
原因:在react.js中props.children不一定是数组
react资深提供了一个react.children.map()方法,可以安全遍历子节点对象。
Immutable.js采用了 持久化数据结构 ,保证每一个对象都是不可变的,任何添加、修改、删除等操作都会生成一个新的对象,且通过 结构共享 等方式大幅提高性能
redux: redux是专门用于集中式管理状态的javascript库,他并不是
react的插件库。
redux三大核心:
actions
actions英文直译过来就是行动、动作的意思,那么我们就可以猜到他表示的是“怎么做”,简单来说actions就是一个对象,actions里面有两个属性分别为type和data:
type:标识属性,值为字符串且唯一,必要属性(你想要做什么事情
data:数据属性,值为任意类型,可选属性(你要做事情的数据
那我们浅浅举个栗子:比如计算器你可以进行加1减2等操作,那么加减乘除这个操作就是你的type,数字就是你的数据
store
store有且只能有一个,他相当于一个最高指挥家,他负责把action动作交给对应的reducer进行执行,也就是说将state、action和reducer联系在一起的对象。
reducer
reducer用于将store发过来的action完成并将结果返回给store,他接收两个参数preState(旧状态)和action(动作)并返回一个newState(新状态)。
工作流程:当组件使用store中的数据需要发生变化时,告诉action生成动作对象,通过dispatch分发对象到store,store对需要使用的reducer进行绑定,然后将action分发到对应reducer上执行相应逻辑进行数据覆盖
,再将store数据渲染
三大原则
唯一数据源(state)
数据源(state)只读
通过纯函数(pure function)改变数据源(state)
react-redux执行流程详解:
初始化阶段:
- 创建 Redux store 对象,并将 Reducer 传入 createStore 函数中。
- 创建一个 Provider 组件,并将 Redux store 对象作为 Provider 组件的 props 传入其中。
- 将应用根组件包装在 Provider 组件中,并渲染整个应用。
运行阶段:
- 使用
connect
函数将组件与 Redux 中的 state 和 action creators 相连接,并将它们转化为组件的 props 属性import { connect } from 'react-redux'; import { addToCart } from '../actions'; const Product = ({ product, addToCart }) => ( <div> <h3>{product.name}</h3> <button onClick={() => addToCart(product)}>Add to cart</button> </div> ); const mapDispatchToProps = { addToCart, }; export default connect(null, mapDispatchToProps)(Product);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
更新阶段:
- 在 Store 的 dispatch 方法中,执行 action 并更新 Store 中的 state。
- React-Redux 根据 Store 中的新状态,检查哪些组件的 props 发生了变化。
- 对于发生变化的组件,React-Redux 将触发相关的生命周期方法和 render 方法进行重新渲染。
工作流程:
使用步骤:
在顶层组件中创建一个 context 对象,并将需要共享的数据挂载到该对象上
const MyContext = React.createContext(defaultValue);
在顶层组件的 render 方法中,使用 MyContext.Provider
组件来包裹整个应用程序,并将共享的数据传递给 value
属性
<MyContext.Provider value={sharedData}>
<App />
</MyContext.Provider>
在需要使用共享数据的组件中,使用 MyContext.Consumer
组件来接收 context 的 value 属性,并在 Consumer 的子元素中使用这些数据
<MyContext.Consumer>
{sharedData => (
// 此处可以使用 sharedData 来操作共享数据
)}
</MyContext.Consumer>
React-Redux 中的 Provider 组件是一个 React 组件,它使用了 React 的 Context API 来实现数据的传递。Provider 组件提供一个 context 对象,它可以让嵌套在它内部的子组件都可以访问到这个 context 对象,并且可以通过它来获取到 Redux store 中的数据。
connect 函数是将 React 组件与 Redux Store 进行连接的重要方法。它接收两个函数作为参数,并返回一个高阶组件,通过这个高阶组件可以将 Redux Store 和 React 组件关联起来。 (实现容器组件包裹ui组件)
在原应用组件上包裹一层,使原来整个应用成为Provider的子组件,接收Redux的store作为props,通过context对象传递给子孙组件上的connect,它真正连接 Redux 和 React,它包在我们的容器组件的外一层,它接收上面 Provider 提供的 store 里面的 state 和 dispatch,传给一个构造函数,返回一个对象,以属性形式传给我们的容器组件。
//其中 mapStateToProps 和 mapDispatchToProps 是将 Store 和 action creator 映射到组件的 props 上的函数。
connect(mapStateToProps, mapDispatchToProps)(Product);
react-toolkit是一个官方维护的包含多个有用工具的 Redux 库,旨在使 React 和 Redux 的开发变得更加简单、高效和直观
redux-toolkit
提供了一种新的方式来编写 Redux 应用程序,该方式包含了常见的 Redux 模式,并通过封装样板代码来简化它们。这使得开发者可以更加专注于实现业务逻辑,而不必关心较低级别的细节。
redux-toolkit
包含了 Redux 应用程序中常用的几个中间件,如 redux-thunk
中间件、redux-saga
中间件和 redux-logger
中间件,使开发者可以轻松地使用和配置这些中间件。
redux-toolkit
的 createSlice
函数在创建 reducer 时会自动使用不可变性(immutability)来更新 state,这避免了因直接修改 state 而产生的潜在错误。
redux-toolkit
提供了 createSlice
函数来创建 reducer,该函数还会自动为每个 action type 创建一个字符串常量,避免手动编写这些常量带来的冗余代码。
redux-toolkit
提供了 createAsyncThunk
函数来创建具有异步副作用的 action,该函数自动处理异步流程,并可以在状态中跟踪每个异步操作的进度和结果。
React.memo
是一个高阶组件,它可以将一个纯函数组件,当组件的 props 没有变化时,会直接复用组件的渲染结果,从而避免不必要的渲染。
//当 MyComponent 的 text 属性没有变化时,MemoizedComponent 就会复用之前的渲染结果,而不会重新渲染。
function MyComponent(props) {
return <div>{props.text}</div>;
}
const MemoizedComponent = React.memo(MyComponent);
useMemo
是一个 Hook,它可以用于缓存计算结果,以避免重复计算。当传入的依赖项没有变化时,会直接返回缓存的结果。
//如果 calculate 方法比较耗时,为了避免不必要的计算,我们可以使用 useMemo 来缓存计算结果:
function MyComponent({ a, b }) {
const result = useMemo(() => calculate(a, b), [a, b]);
return <div>{result}</div>;
}
区别:
React.memo
和 useMemo
都可以用于优化 React 应用的性能,但是它们的优化对象和优化手段不同。React.memo
通过避免组件的不必要渲染来提高性能,而 useMemo
通过避免重复计算来提高性能。在实际开发中,需要根据具体场景和需求来选择适合的优化方法。
useCallback
用于缓存函数,以避免不必要的函数创建和渲染。当依赖项发生变化时,会返回一个新的函数引用,否则直接返回之前缓存的函数引用。
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
useMemo
用于缓存计算结果,以避免重复计算和渲染。当依赖项发生变化时,会重新计算并返回新的计算结果
const memoizedValue = useMemo(() => {
return heavyComputation(a, b);
}, [a, b]);
useCallback
通过避免函数创建和渲染来提高性能,而 useMemo
通过避免重复计算和渲染来提高性能
ref 是用来访问 DOM 元素或组件实例的引用的一种方式。
字符串回调
class MyComponent extends React.Component {
componentDidMount() {
console.log(this.refs.myInput);
// 输出:<input type="text" />
}
render() {
return <input type="text" ref="myInput" />;
}
}
函数回调
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = null;
}
componentDidMount() {
console.log(this.myRef);
// 输出:<input type="text" />
}
render() {
return <input type="text" ref={node => this.myRef = node} />;
}
}
React.createRef
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
console.log(this.myRef.current);
// 输出:<input type="text" />
}
render() {
return <input type="text" ref={this.myRef} />;
}
}
原因:
循环、条件语句等块级作用域会影响 Hooks 调用的次数和顺序,从而破坏 React 内部的依赖关系和渲染逻辑,导致组件出现无法预期的错误。因此,为了保证组件能够正常渲染和更新,我们需要遵循 React Hooks 的使用规范,在顶层作用域中调用 Hooks。
使用第三方库: React Transition Group 详细学习过度动画
注意: CSSTransition 中类命名方式classNames
React 的懒加载实现原理主要是基于 ES6 的 import()
函数和 React 的 lazy
函数。
import React, { lazy, Suspense } from "react";
const LazyComponent = lazy(() => import("./LazyComponent"));
function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
当我们使用 lazy
函数时,React 会在运行时动态创建一个新的组件,这个新的组件继承了原始组件的所有属性和方法,并且它的 render 方法被重写成一个异步函数。当这个新的组件需要被渲染时,React 就会自动触发它的 render 方法,这个方法会异步加载原始组件的代码,并将其渲染到页面上。
这里涉及到了 ES6 中的 import()
函数,它是一个异步函数,用来动态加载 JavaScript 模块。import()
函数会返回一个 Promise 对象,当模块加载完成后,Promise 对象就会被 resolve,我们可以通过 then 方法获取模块的默认导出对象。
Immutable 是一个 JavaScript 库,它提供了一些数据结构和 API,使得创建不可变数据
成为可能。React 中使用 Immutable 可以带来以下好处:
immutable创建不可变数据类型,想要修改只能通过数据覆盖创建新的变量,对react进行性能优化
原因:React 团队认为,使用数组可以带来更好的灵活性和易用性
优点:
Hooks 是基于函数式编程思想设计的,不支持类组件的一些特性。但是,React 提供了一些方法,可以让开发者在类组件中使用 Hooks 的部分功能,或者将类组件转换为函数组件来使用 Hooks。
redux-thunk
的设计思路是将异步逻辑封装到“thunk”函数中,这个函数接收 dispatch
方法作为参数,并返回一个带有回调函数的函数。这个回调函数在异步操作完成后被调用,然后再通过 dispatch
方法触发一个 action,更新 Redux store 中的数据。redux-thunk
适合用于处理简单的异步逻辑,比如发送 AJAX 请求或者获取本地存储数据等。 没有拓展api
redux-saga
则采用了另外一种设计思路,它使用了 ES6 的 generator 函数来实现异步逻辑的管理。在 redux-saga
中,使用 generator 函数定义一个 saga,它可以监听一个或多个 action,并在相应的 action 被触发后执行一些副作用,比如发送 AJAX 请求、触发其他 action 等。redux-saga
还提供了一些辅助函数和特性(api),比如 takeLatest
、put
、call
等,使得开发者可以更加方便地管理异步流程,处理错误和取消请求等。
React 合成事件(SyntheticEvent)是 React 模拟原生 DOM 事件所有能力的一个事件对象
使用原因:
进行浏览器兼容,实现更好的跨平台
React 采用的是顶层事件代理
机制,能够保证冒泡一致性,可以跨浏览器执行。React 提供的合成事件用来抹平不同浏览器事件对象之间的差异,将不同平台事件模拟合成事件。
避免垃圾回收
事件对象可能会被频繁创建和回收,因此 React 引入事件池
,在事件池中获取或释放事件对象。即 React 事件对象不会被释放掉,而是存放进一个数组
中,当事件触发,就从这个数组中弹出,避免频繁地去创建和销毁(垃圾回收)。
方便事件统一管理和事务机制
原理:
React 并不会把所有的处理函数直接绑定在真实的节点上。而是把所有的事件绑定到结构的最外层,使用一个统一的事件监听器,这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。
id = root
的DOM元素中(网上很多说是在document
中,17
版本不是了);id = root
的DOM元素中触发;React
自身实现了一套事件冒泡捕获机制;React
实现了合成事件SyntheticEvent
;React
在17
版本不再使用事件池了(网上很多说使用了对象池来管理合成事件对象的创建销毁,那是16
版本及之前);id = root
的DOM元素中委托,其实是一直在触发的,只是没有绑定对应的回调函数;import React, { useRef, useEffect } from "react"; import "./styles.css"; const logFunc = (target, isSynthesizer, isCapture = false) => { const info = `${isSynthesizer ? "合成" : "原生"}事件,${ isCapture ? "捕获" : "冒泡"}阶段,${target}元素执行了`; console.log(info); }; const batchManageEvent = (targets, funcs, isRemove = false) => { targets.forEach((target, targetIndex) => { funcs[targetIndex].forEach((func, funcIndex) => { target[isRemove ? "removeEventListener" : "addEventListener"]( "click", func, !funcIndex ); }); }); }; export default function App() { const divDom = useRef(); const h1Dom = useRef(); useEffect(() => { const docClickCapFunc = () => logFunc("document", false, true); const divClickCapFunc = () => logFunc("div", false, true); const h1ClickCapFunc = () => logFunc("h1", false, true); const docClickFunc = () => logFunc("document", false); const divClickFunc = () => logFunc("div", false); const h1ClickFunc = () => logFunc("h1", false); batchManageEvent( [document, divDom.current, h1Dom.current], [ [docClickCapFunc, docClickFunc], [divClickCapFunc, divClickFunc], [h1ClickCapFunc, h1ClickFunc] ] ); return () => { batchManageEvent( [document, divDom.current, h1Dom.current], [ [docClickCapFunc, docClickFunc], [divClickCapFunc, divClickFunc], [h1ClickCapFunc, h1ClickFunc] ], true ); }; }, []); return ( <div ref={divDom} className="App1" onClickCapture={() => logFunc("div", true, true)} onClick={() => logFunc("div", true)} > <h1 ref={h1Dom} onClickCapture={() => logFunc("h1", true, true)} onClick={() => logFunc("h1", true)} > Hello CodeSandbox </h1> </div> ); }
React16
React17
总结
16
版本先执行原生事件,当冒泡到document
时,统一执行合成事件,17
版本在原生事件执行前先执行合成事件捕获阶段,原生事件执行完毕执行冒泡阶段的合成事件,通过根节点来管理所有的事件JSX即JavaScript XML。一种在React组件内部构建标签的类XML语法。JSX为react.js开发的一套语法糖
,也是react.js的使用基础。React在不使用JSX的情况下一样可以工作,然而使用JSX可以提高组件的可读性,因此推荐使用JSX。
优点:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。