We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
当数据发生变化,比如setState时,会引起组件重新渲染,整个UI都会以virtual dom的形式重新渲染;
然后收集差异,也就是diff新的virtual dom和老的virtual dom的差异;
最后把差异队列里的差异,比如增加节点、删除节点、移动节点更新到真实的DOM上;
setState实际上是异步的,这是为了提升react底层的性能,是为了防止时间间隔很短的情况下-多次改变state,React会在这种情况下将几次改变state合并成一次从而提高性能。
https://juejin.cn/post/6844903816857403405#heading-4
1, diff算法是同级比较,假设第一层两个虚拟DOM节点不一致,就不会往下比了,就会将原始页面虚拟DOM全部删除掉,然后用新的虚拟DOM进行全部的替换,虽然这有可能有一些性能的浪费,但是由于同层比对的算法性能很高,因此又弥补了性能的损耗。
2, 比较key: 做list循环的时候有一个key值,这样比对的时候就可以相对应的比对,找出要改变的,以及不需要渲染的,这样使用key做关联,极大的提升了虚拟DOM比对的性能,这要保证在新的虚拟DOM后key值不变,这就说明了为什么做list循环的时候key的值不要是index,因为这样没有办法保证原虚拟DOM和新虚拟DOM的key值一致性,而造成性能的损耗,一般这个key对应后台数据的唯一id字段,而不是循环的index。
举例说明:
变化前数组的值是[1,2,3,4],key就是对应的下标:0,1,2,3 变化后数组的值是[4,3,2,1],key对应的下标也是:0,1,2,3
Props 是 React 中属性的简写。
它们是只读的,即不可变。
它们总是在整个应用中从父组件传递到子组件。
子组件永远不能将 prop 送回父组件。这有助于维护单向数据流,通常用于呈现动态生成的数据。
less继承
sticky
服务器端渲染
promise.all
react setState 异步
useCallback
缓存
发生了什么
dns
跨域
history
组件是由元素构成的。
元素数据结构是普通对象,
而组件数据结构是类或纯函数。
元素是虚拟dom。
它是 React 中最小基本单位,可以使用 JSX 语法创建一个 React 元素:
const element = <div className="element">I'm element</div>
React 元素不是真实的 DOM 元素,它仅仅是 js 的普通对象(plain objects),所以也没办法直接调用 DOM 原生的 API。上面的 JSX 转译后的对象大概是这样的:
{ _context: Object, _owner: null, key: null, props: { className: 'element', children: 'I'm element' }, ref: null, type: "div" }
除了使用 JSX 语法,我们还可以使用 React.createElement() 和 React.cloneElement() 来构建 React 元素。
React 中有三种构建组件的方式。React.createClass()、ES6 class和函数组件。
https://www.jianshu.com/p/41776f2f4d8b
https://cloud.tencent.com/developer/article/1516369
当某个事件触发时,文档根节点最先接受到事件,然后根据DOM树结构向具体绑定事件的元素传递。
该阶段为父元素截获事件提供了机会。 事件传递路径为: window —> document —> boy —> div—> text
具体元素已经捕获事件。之后事件开始向根节点冒泡。
该阶段的开始即是事件的开始,根据DOM树结构由具体触发事件的元素向根节点传递。 事件传递路径: text—> div —> body —> document —> window
React将事件绑定到了document上。并没有绑定到具体的dom节点上。
基于浏览器的事件冒泡机制(冒泡),所有节点的事件都会在 document 上触发。
然后由统一的事件处理程序来处理(主要是dispatchEvent);
所以当事件触发的时候,分发函数dispatchEvent将指定函数执行。
react利用事件的冒泡机制,将事件处理函数绑定到document上,使用一个统一的事件监听器(dispatchEvent):
document
dispatchEvent
1.维持了映射保存所有组件内的事件监听和处理函数;
2.组件挂载、卸载的时,只是在监听器(dispatchEvent)上插入或删除一些对象;
3.事件触发时,由监听器(dispatch)分发事件并调用相应的方法;
统一规范,解决 ie 事件兼容问题,简化事件逻辑
简化了事件处理和回收机制,效率大大提升。
减少内存消耗,提升性能,不需要注册那么多的事件了,一种事件类型只在 document 上注册一次
合成事件是对原生事件的封装;
并对某些原生事件进行了升级和改造,使之能兼容不同的浏览器。
访问原生事件对象
,有两种方式阻止冒泡,
和
e.stopPropagation只能阻止向父级元素冒泡, 而stopImmediatePropagation不仅可以阻止向父级元素冒泡,还能阻止自身元素剩余的其他事件的执行。
e.stopPropagation只能阻止向父级元素冒泡,
e.stopPropagation
而stopImmediatePropagation不仅可以阻止向父级元素冒泡,还能阻止自身元素剩余的其他事件的执行。
stopImmediatePropagation
原生事件总是比合成事件先执行
如果一个节点上同时绑定了合成和原生事件,那么禁止冒泡后执行关系是怎样的呢?
原生事件(阻止冒泡)会阻止合成事件的执行
合成事件(阻止冒泡)不会阻止原生事件的执行。
原因:
浏览器事件的执行需要经过三个阶段,捕获阶段-目标元素阶段-冒泡阶段。
节点上的原生事件的执行是在目标阶段,然而合成事件的执行是在冒泡阶段,所以原生事件会先合成事件执行,然后再往父节点冒泡。
既然原生都阻止冒泡了,那合成还执行个啥嘞。
好,轮到合成的被阻止冒泡了,那原生会执行吗?当然会了。
因为原生的事件先于合成的执行,所以合成事件内阻止的只是合成的事件冒泡。
(1)命名规范不同 React事件的属性名是采用驼峰形式的,事件处理函数是一个函数; 原生事件通过addEventListener给事件添加事件处理函数
(2)React事件只支持事件冒泡。原生事件通过配置第三个参数,true为事件捕获,false为事件冒泡;
(3)事件挂载目标不同
(4)this指向不同
部分 UI 中的 JavaScript 错误不应该破坏整个应用程序。
为了解决这个问题,React 16引入了一个 “错误边界(Error Boundaries)” 的新概念。
componentDidCatch(err,info) { this.setState({hasError: true}); }
增加dangerouslySetInnerHTML属性,并且传入对象的属性名叫_html
function Component(props){ return <div dangerouslySetInnerHTML={{_html:'<span>你好</span>'}}> </div> }
useReducer是 useState 的另一种替代。 它接受(state, action) => newState,并且返回了一个与当前state成对的dispatch的方法。
如果想要组件之间共享状态,可以使用useContext。
简单来说Context的作用就是对它所包含的组件树提供全局共享数据的一种技术, 类似一个全局store,useContext和useReducer可以实现redux。
useCallback 和 useMemo基本是一样的,都是对组件进行性能优化的; 应用场景:父组件向子组件传值时,父组件render会导致子组件也会跟着render,不管传的值是否发生改变,子组件都会render,造成资源的浪费。用useCallback 和 useMemo可以监控传值情况,对其进行缓存,传值没有改变时,会阻止子组件render。
两者区别在于:useCallback是对字面量进行缓存,而useMemo是对其进行计算缓存。 简单来说就是useCallback直接缓存函数,useMemo缓存函数的返回值
(useMemo有是的作用是什么呢?是避免在每次渲染时都进行高开销的计算的优化的策略,) 🤔大伙应该明白了useCallback的作用了,配合memo用于优化子组件的渲染次数
需要传入两个参数
const handleChildrenCallback = useCallback(() => { handleChildren(); }, []);// 咱们不需要就不要传入
返回一个 memoized 回调函数。在依赖参数不变的情况下,返回的回调函数是同一个引用地址
注意 每当依赖参数发生改变useCallback就会自动重新返回一个新的 memoized 函数(地址发生改变)
1、作为props,传递给子组件,为避免子元素不必要的渲染,需要配合React.Memo或者useMemo使用,否则无意义:
React.Memo
useMemo
2、作为useEffect的依赖项,需要进行比较的时候才需要加上useCallback;
useEffect
Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的钩子。
.current
转发 ref 给子组件用的,俗称 ref 转发;
是父组件用来获取子组件的dom元素的:
// 子组件 const Child = React.forwardRef((props, ref) => ( <input ref={ref} /> )); // 父组件 import React, { useRef, useEffect } from 'react'; function Father() { const myRef = useRef(null); effect(() => { if (myRef.current) { console.log(myRef.current); } }, []); return <Child ref={myRef} /> }
此时父组件的this.myRef.current的值是input这个DOM元素
Ref 转发 是让某些组件(Child)可以使用它们接收的 ref 的特性,这些组件还可以进一步将其传递给子组件。
ref
findDOMNode()
最好使用 refs 回调 而不是 findDOMNode() API。
因为 findDOMNode() 将来会阻止对 React 的某些改进。而且`findDOMNode使用了this,已经不适用新版本的react。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
virtual DOM 如何工作
当数据发生变化,比如setState时,会引起组件重新渲染,整个UI都会以virtual dom的形式重新渲染;
然后收集差异,也就是diff新的virtual dom和老的virtual dom的差异;
最后把差异队列里的差异,比如增加节点、删除节点、移动节点更新到真实的DOM上;
setState实际上是异步
setState实际上是异步的,这是为了提升react底层的性能,是为了防止时间间隔很短的情况下-多次改变state,React会在这种情况下将几次改变state合并成一次从而提高性能。
Fiber
https://juejin.cn/post/6844903816857403405#heading-4
diff算法
1, diff算法是同级比较,假设第一层两个虚拟DOM节点不一致,就不会往下比了,就会将原始页面虚拟DOM全部删除掉,然后用新的虚拟DOM进行全部的替换,虽然这有可能有一些性能的浪费,但是由于同层比对的算法性能很高,因此又弥补了性能的损耗。
2, 比较key: 做list循环的时候有一个key值,这样比对的时候就可以相对应的比对,找出要改变的,以及不需要渲染的,这样使用key做关联,极大的提升了虚拟DOM比对的性能,这要保证在新的虚拟DOM后key值不变,这就说明了为什么做list循环的时候key的值不要是index,因为这样没有办法保证原虚拟DOM和新虚拟DOM的key值一致性,而造成性能的损耗,一般这个key对应后台数据的唯一id字段,而不是循环的index。
举例说明:
什么是 Props?
Props 是 React 中属性的简写。
它们是只读的,即不可变。
它们总是在整个应用中从父组件传递到子组件。
子组件永远不能将 prop 送回父组件。这有助于维护单向数据流,通常用于呈现动态生成的数据。
React主要优点
上下文Context
less继承
sticky
服务器端渲染
promise.all
react setState 异步
useCallback
缓存
发生了什么
dns
跨域
history
元素与组件
组件是由元素构成的。
元素数据结构是普通对象,
而组件数据结构是类或纯函数。
元素
元素是虚拟dom。
它是 React 中最小基本单位,可以使用 JSX 语法创建一个 React 元素:
React 元素不是真实的 DOM 元素,它仅仅是 js 的普通对象(plain objects),所以也没办法直接调用 DOM 原生的 API。上面的 JSX 转译后的对象大概是这样的:
除了使用 JSX 语法,我们还可以使用 React.createElement() 和 React.cloneElement() 来构建 React 元素。
组件
React 中有三种构建组件的方式。React.createClass()、ES6 class和函数组件。
事件
https://www.jianshu.com/p/41776f2f4d8b
https://cloud.tencent.com/developer/article/1516369
浏览器事件机制
1、事件捕获阶段
当某个事件触发时,文档根节点最先接受到事件,然后根据DOM树结构向具体绑定事件的元素传递。
该阶段为父元素截获事件提供了机会。
事件传递路径为:
window —> document —> boy —> div—> text
2、目标阶段
具体元素已经捕获事件。之后事件开始向根节点冒泡。
3、事件冒泡阶段
该阶段的开始即是事件的开始,根据DOM树结构由具体触发事件的元素向根节点传递。
事件传递路径:
text—> div —> body —> document —> window
react事件
React将事件绑定到了document上。并没有绑定到具体的dom节点上。
基于浏览器的事件冒泡机制(冒泡),所有节点的事件都会在 document 上触发。
然后由统一的事件处理程序来处理(主要是dispatchEvent);
所以当事件触发的时候,分发函数dispatchEvent将指定函数执行。
dispatchEvent
react利用事件的冒泡机制,将事件处理函数绑定到
document
上,使用一个统一的事件监听器(dispatchEvent
):1.维持了映射保存所有组件内的事件监听和处理函数;
2.组件挂载、卸载的时,只是在监听器(dispatchEvent)上插入或删除一些对象;
3.事件触发时,由监听器(dispatch)分发事件并调用相应的方法;
优点:
统一规范,解决 ie 事件兼容问题,简化事件逻辑
简化了事件处理和回收机制,效率大大提升。
减少内存消耗,提升性能,不需要注册那么多的事件了,一种事件类型只在 document 上注册一次
合成事件 vs 原生事件
合成事件是什么?
合成事件是对原生事件的封装;
并对某些原生事件进行了升级和改造,使之能兼容不同的浏览器。
访问原生事件对象
e`;,有两种方式阻止冒泡,
e.stopPropagation和
stopImmediatePropagation`,两者的区别是:原生事件总是比合成事件先执行
禁止冒泡会怎样?
如果一个节点上同时绑定了合成和原生事件,那么禁止冒泡后执行关系是怎样的呢?
原生事件(阻止冒泡)会阻止合成事件的执行
合成事件(阻止冒泡)不会阻止原生事件的执行。
原因:
浏览器事件的执行需要经过三个阶段,捕获阶段-目标元素阶段-冒泡阶段。
节点上的原生事件的执行是在目标阶段,然而合成事件的执行是在冒泡阶段,所以原生事件会先合成事件执行,然后再往父节点冒泡。
既然原生都阻止冒泡了,那合成还执行个啥嘞。
好,轮到合成的被阻止冒泡了,那原生会执行吗?当然会了。
因为原生的事件先于合成的执行,所以合成事件内阻止的只是合成的事件冒泡。
两者不同
(1)命名规范不同
React事件的属性名是采用驼峰形式的,事件处理函数是一个函数;
原生事件通过addEventListener给事件添加事件处理函数
(2)React事件只支持事件冒泡。原生事件通过配置第三个参数,true为事件捕获,false为事件冒泡;
(3)事件挂载目标不同
(4)this指向不同
错误边界(Error Boundaries)
部分 UI 中的 JavaScript 错误不应该破坏整个应用程序。
为了解决这个问题,React 16引入了一个 “错误边界(Error Boundaries)” 的新概念。
如何在React中使用innerHTML
增加dangerouslySetInnerHTML属性,并且传入对象的属性名叫_html
useReducer
useReducer是 useState 的另一种替代。
它接受(state, action) => newState,并且返回了一个与当前state成对的dispatch的方法。
useContext
如果想要组件之间共享状态,可以使用useContext。
简单来说Context的作用就是对它所包含的组件树提供全局共享数据的一种技术,
类似一个全局store,useContext和useReducer可以实现redux。
useCallback
useCallback 和 useMemo基本是一样的,都是对组件进行性能优化的;
应用场景:父组件向子组件传值时,父组件render会导致子组件也会跟着render,不管传的值是否发生改变,子组件都会render,造成资源的浪费。用useCallback 和 useMemo可以监控传值情况,对其进行缓存,传值没有改变时,会阻止子组件render。
两者区别在于:useCallback是对字面量进行缓存,而useMemo是对其进行计算缓存。
简单来说就是useCallback直接缓存函数,useMemo缓存函数的返回值
(useMemo有是的作用是什么呢?是避免在每次渲染时都进行高开销的计算的优化的策略,)
🤔大伙应该明白了useCallback的作用了,配合memo用于优化子组件的渲染次数
需要传入两个参数
useCallback 返回值
返回一个 memoized 回调函数。在依赖参数不变的情况下,返回的回调函数是同一个引用地址
useCallback使用场景
1、作为props,传递给子组件,为避免子元素不必要的渲染,需要配合
React.Memo
或者useMemo
使用,否则无意义:2、作为
useEffect
的依赖项,需要进行比较的时候才需要加上useCallback
;useMemo
和useCallback不同之处
Refs
refs 干嘛用的?
Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的钩子。
useRef
.current
属性不会引发组件重新渲染。refs ( forwardRef Refs ) 转发是什么?
转发 ref 给子组件用的,俗称 ref 转发;
是父组件用来获取子组件的dom元素的:
此时父组件的this.myRef.current的值是input这个DOM元素
Ref 转发 是让某些组件(Child)可以使用它们接收的
ref
的特性,这些组件还可以进一步将其传递给子组件。refs 和
findDOMNode()
哪个是首选项?最好使用 refs 回调 而不是
findDOMNode()
API。因为
findDOMNode()
将来会阻止对 React 的某些改进。而且`findDOMNode使用了this,已经不适用新版本的react。The text was updated successfully, but these errors were encountered: