事件机制
在doucument处监听了所有的事件,当事件发生并冒泡到document处的时候,react将事件内容封装,并交给真正的处理函数运行。这样减少了内存的消耗,还能再组件挂载销毁时统一订阅和移除事件。
冒泡到document的事件也不是浏览器原生事件,而是react自己实现的合成事件。
React事件与普通HTML事件有什么不同
- 事件命名:原生事件全小写,react事件小驼峰
- 事件处理函数:原生事件字符串,react事件为函数
- react事件不能用return false组织浏览器的默认行为,必须用
preventDefault()
来阻止默认行为
合成事件是react模拟原生DOM事件所有能力的一个事件对象,优点如下:
- 兼容所有浏览器,更好的跨平台
- 将事件统一存放在一个数组,避免频繁的新增与删除
- 方便react统一管理和事物机制
react组件怎么事件代理,原理
react底层,对合成事件做了两件事:
事件委派:react把所有的事件绑定到解构的最外层,使用统一的事件监听器,这个事件监听器上维持了一个映射来保存所有组件内部事件监听和处理函数
自动绑定:react组件中,每个方法的上下文都会指向该组件的实力,自动绑定this为当前组件
React 高阶组件、Render props、hooks 有什么区别,为什么要不断迭代
这三者是目前react解决代码复用的主要方式
- 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。具体而言,高阶组件是参数为组件,返回值为新组件的函数。(包装组件)
// hoc的定义
function withSubscription(WrappedComponent, selectData) {
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
data: selectData(DataSource, props)
};
}
// 一些通用的逻辑处理
render() {
// ... 并使用新数据渲染被包装的组件!
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
// 使用
const BlogPostWithSubscription = withSubscription(BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id));
- render props是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术,更具体的说,render prop 是一个用于告知组件需要渲染什么内容的函数 prop。(组件作为另一个组件的参数)
// DataProvider组件内部的渲染逻辑如下
class DataProvider extends React.Components {
state = {
name: 'Tom'
}
render() {
return (
<div>
<p>共享数据组件自己内部的渲染逻辑</p>
{ this.props.render(this.state) }
</div>
);
}
}
// 调用方式
<DataProvider render={data => (
<h1>Hello {data.name}</h1>
)}/>
Hooks
它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。通过自定义hook,可以复用代码逻辑。
// 自定义一个获取订阅数据的hook
function useSubscription() {
const data = DataSource.getComments();
return [data];
}
//
function CommentList(props) {
const {data} = props;
const [subData] = useSubscription();
...
}
// 使用
<CommentList data='hello' />
对React-Fiber的理解,它解决了什么问题?
不让一个任务长期霸占资源,可以将浏览器的操作视作进程,通过某些调度策略分配cpu资源,从而提高浏览器的用户相应速率。
核心思想: Fiber 也称协程或者纤程。它和线程并不一样,协程本身是没有并发或者并行能力的(需要配合线程),它只是一种控制流程的让出机制。让出 CPU 的执行权,让 CPU 能在这段时间执行其他的操作。渲染的过程可以被中断,可以将控制权交回浏览器,让位给高优先级的任务,浏览器空闲后再恢复渲染。
Component, Element, Instance 之间有什么区别和联系?
- 元素: 一个元素
element
是一个普通对象(plain object),描述了对于一个DOM节点或者其他组件component
,你想让它在屏幕上呈现成什么样子。元素element
可以在它的属性props
中包含其他元素(译注:用于形成元素树)。创建一个React元素element
成本很低。元素element
创建之后是不可变的。 - 组件: 一个组件
component
可以通过多种方式声明。可以是带有一个render()
方法的类,简单点也可以定义为一个函数。这两种情况下,它都把属性props
作为输入,把返回的一棵元素树作为输出。 - 实例: 一个实例
instance
是你在所写的组件类component class
中使用关键字this
所指向的东西(译注:组件实例)。它用来存储本地状态和响应生命周期事件很有用。
React.createClass和extends Component的区别有哪些?
React.createClass和extends Component的bai区别主要在于:
(1)语法区别
- createClass本质上是一个工厂函数,extends的方式更加接近最新的ES6规范的class写法。两种方式在语法上的差别主要体现在方法的定义和静态属性的声明上。
- createClass方式的方法定义使用逗号,隔开,因为creatClass本质上是一个函数,传递给它的是一个Object;而class的方式定义方法时务必谨记不要使用逗号隔开,这是ES6 class的语法规范。
(2)propType 和 getDefaultProps
- React.createClass:通过proTypes对象和getDefaultProps()方法来设置和获取props.
- React.Component:通过设置两个属性propTypes和defaultProps
(3)状态的区别
- React.createClass:通过getInitialState()方法返回一个包含初始值的对象
- React.Component:通过constructor设置初始状态
(4)this区别
- React.createClass:会正确绑定this
- React.Component:由于使用了 ES6,这里会有些微不同,属性并不会自动绑定到 React 类的实例上。
(5)Mixins
- React.createClass:使用 React.createClass 的话,可以在创建组件时添加一个叫做 mixins 的属性,并将可供混合的类的集合以数组的形式赋给 mixins。
- 如果使用 ES6 的方式来创建组件,那么
React mixins
的特性将不能被使用了。
哪些方法会触发 React 重新渲染?重新渲染 render 会做些什么?
哪些方法会触发 react 重新渲染?
- setState()方法被调用
- 父组件重新渲染
重新渲染 render 会做些什么?
- 会对新旧 VNode 进行对比,也就是我们所说的Diff算法。
- 对新旧两棵树进行一个深度优先遍历,这样每一个节点都会一个标记,在到深度遍历的时候,每遍历到一和个节点,就把该节点和新的节点树进行对比,如果有差异就放到一个对象里面
- 遍历差异对象,根据差异的类型,根据对应对规则更新VNode
组件声名的几种方法
React 声明组件的三种方式:
- 函数式定义的
无状态组件
- ES5原生方式
React.createClass
定义的组件 - ES6形式的
extends React.Component
定义的组件
(1)无状态函数式组件 它是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到state状态的操作 组件不会被实例化,整体渲染性能得到提升,不能访问this对象,不能访问生命周期的方法
(2)ES5 原生方式 React.createClass // RFC React.createClass会自绑定函数方法,导致不必要的性能开销,增加代码过时的可能性。
(3)E6继承形式 React.Component // RCC 目前极为推荐的创建有状态组件的方式,最终会取代React.createClass形式;相对于 React.createClass可以更好实现代码复用。
无状态组件相对于于后者的区别: 与无状态组件相比,React.createClass和React.Component都是创建有状态的组件,这些组件是要被实例化的,并且可以访问组件的生命周期方法。
React.createClass与React.Component区别:
① 函数this自绑定
- React.createClass创建的组件,其每一个成员函数的this都有React自动绑定,函数中的this会被正确设置。
- React.Component创建的组件,其成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。
② 组件属性类型propTypes及其默认props属性defaultProps配置不同
- React.createClass在创建组件时,有关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是使用getDefaultProps的方法来获取默认组件属性的
- React.Component在创建组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。
③ 组件初始状态state的配置不同
- React.createClass创建的组件,其状态state是通过getInitialState方法来配置组件相关的状态;
- React.Component创建的组件,其状态state是在constructor中像初始化组件属性一样声明的。
对React的插槽(Portals)的理解,如何使用,有哪些使用场景
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案
child:可渲染的react子项
container:Dom元素
ReactDOM.createPortal(child, container);
//一般情况下,组件的render函数返回的元素会被挂载在它的父级组件上:
import DemoComponent from './DemoComponent';
render() {
// DemoComponent元素会被挂载在id为parent的div的元素上
return (
<div id="parent">
<DemoComponent />
</div>
);
}
//有些元素需要被挂载在更高层级的位置
import DemoComponent from './DemoComponent';
render() {
// DemoComponent元素会被挂载在id为parent的div的元素上
return (
<div id="parent">
<DemoComponent />
</div>
);
}