原文见:语雀(https://www.yuque.com/deepstates/interview/hia3k3)
● 核心概念
○ 元素渲染、组件、props、state
○ refs:使用场景、如何创建、如何访问
○ 组件通信:父子、祖孙、兄弟组件通信
○ 生命周期、事件处理、条件渲染、列表的key、表单、状态提升、组合&继承
⭐️⭐️⭐️ 相关知识参考:
说说你对react的理解?
是什么:react是构建用户界面的js库
能干什么:可以用组件化的方式构建快速响应的web应用程序
如何干:声明式(jsx) 组件化(方便拆分和复用 高内聚 低耦合) 一次学习随处编写
做的怎么样: 优缺(社区繁荣 一次学习随处编写 api简介)缺点(没有系统解决方案 选型成本高 过于灵活)
设计理念:跨平台(虚拟dom) 快速响应(异步可中断 增量更新)
性能瓶颈:cpu io fiber时间片 concurrent mode
渲染过程:scheduler render commit Fiber架构
React有什么特点?
● 声明式设计:react采用范式声明,开发者只需要声明显示内容,react就会自动完成
● 高效: react通过对dom的模拟(也就是虚拟dom),最大限度的减少与dom的交互
● 灵活: react可以和已知的库或者框架很好配合
● 组件: 通过react构建组件,让代码更容易复用,能够很好应用在大型项目开发中,把页面功能拆分成小模块 每个小模块就是组件
● 单向数据流: react是单向数据流,数据通过props从父节点传递到子节点,如果父级的某个props改变了,react会重新渲染所有的子节点
列出React的一些主要优点?
React有哪些限制?
如何模块化 React 中的代码?
可以使用export、import属性来模块化代码。它们有助于在不同的文件中单独编写组件。
对 React-Intl 的理解,它的工作原理?
● React-intl是雅虎的语言国际化开源项目FormatJS的一部分,通过其提供的组件和API可以与ReactJS绑定。
● React-intl提供了两种使用方法,一种是引用React组件,另一种是直接调取API,官方更加推荐在React项目中使用前者,只有在无法使用React组件的地方,才应该调用框架提供的API。它提供了一系列的React组件,包括数字格式化、字符串格式化、日期格式化等。
● 在React-intl中,可以配置不同的语言包,他的工作原理就是根据需要,在语言包之间进行切换。
区别
react vs vue?/ vue 与react的区别?(大华、阿里)
一、相同点:
● 都支持服务器渲染
● 都有虚拟dom,组件化开发,通过props参数进行父子组件数据的传递,都实现webcomponent规范
● 都是数据驱动视图
● 都有状态管理,react有redux,vue有vuex
● 都有支持native的方案 react有react native vue有weex
二、不同点:
● react严格上只针对mvc的view层,vue是mvvm模式
● 模板渲染方式不同
○ 模板的语法不同,React是通过jsx渲染,vue是通过一种拓展的html语法进行渲染。
○ 模板的原理不同:React是在组件JS代码中,通过原生JS实现模板中的常见语法,如插值、条件、循环等,都是通过JS语法实现的,更加纯粹更加原生。Vue是在和组件JS代码分离的单独的模板中,通过指令来实现的,比如条件语句就需要v-if来实现这一点。
● 虚拟dom不一样,vue会跟踪每一个组件的依赖关系,不需要重新渲染整个dom组件树,而react不同,当应用的状态被改变时,全部组件都会重新渲染,所以react中用shouldcomponentupdate这个生命周期的钩子函数来控制
● 组件写法不一样 ,react是jsx和inline style ,就是把html和css全写进js中,vue则是html,css ,js在同一个文件
● 数据绑定不一样,vue实现了数据双向绑定,react数据流动是单向的
● 在react中,state对象需要用setstate方法更新状态,在vue中,state对象不是必须的,数据由data属性在vue对象中管理
vue, react 适用场景? / vue, react 技术选型?
● 应用需要尽可能小和快就用vue, vue渲染速度比react 快
● 大型项目建议用react,因为vue模板的使用不容易发现错误、也不易拆分和测试
● 如果要适用于web 和原生app的项目,就使用react native
vue、react的区别和联系?()
vue, react的模板渲染、两者的虚拟dom、diff差异(vue2、vue3、react16)、两者的批量更新,还有路由差异、常用的优化手段、怎么进行数据通信、讲点新鲜的内容:vue3有什么特性、最后总结,谈谈两者的如今的生态。。。
React核心
核心概念
组件
你对组件的理解?
可组合,可复用,可维护,可测试
React声明组件有哪几种方法,有什么不同?/ React中有哪几种构建组件的方式?
一、React 声明组件的三种方式:
● 无状态函数式组件
○ 它是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到state状态的操作
○ 组件不会被实例化,整体渲染性能得到提升,不能访问this对象,不能访问生命周期的方法
● ES5 原生方式 React.createClass定义的组件 // RFC
○ React.createClass会自绑定函数方法,导致不必要的性能开销,增加代码过时的可能性。
● ES6继承形式 extends React.Component定义的组件 // RCC
○ 目前极为推荐的创建有状态组件的方式,最终会取代React.createClass形式;相对于 React.createClass可以更好实现代码复用。
二、区别
1、无状态组件相对于于后者的区别:
(1)与无状态组件相比,React.createClass和React.Component都是创建有状态的组件,这些组件是要被实例化的,并且可以访问组件的生命周期方法。
2、React.createClass与React.Component区别:
(1)函数this自绑定
● React.createClass创建的组件,其每一个成员函数的this都有React自动绑定,函数中的this会被正确设置。
● React.Component创建的组件,其成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。
(2)组件属性类型propTypes及其默认props属性defaultProps配置不同
● React.createClass在创建组件时,有关组件props的属性类型及组件默认的属性会作为组件实例的属性来配置,其中defaultProps是使用getDefaultProps的方法来获取默认组件属性的
● React.Component在创建组件时配置这两个对应信息时,他们是作为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。
(3)组件初始状态state的配置不同
● React.createClass创建的组件,其状态state是通过getInitialState方法来配置组件相关的状态;
● React.Component创建的组件,其状态state是在constructor中像初始化组件属性一样声明的。
React 中构建组件的方式?
● 自定义组件:函数组件或者无状态组件 ,组件首字母大写
● 类组件:一个类组件必须实现一个render方法,这个方法必须返回一个jsx元素,要用一个外层的元素把所有内容包裹起来
你怎样理解“在React中,一切都是组件”这句话?
Component, Element, Instance 之间有什么区别和联系?
● 元素:一个元素element是一个普通对象(plain object),描述了对于一个DOM节点或者其他组件component,你想让它在屏幕上呈现成什么样子。元素element可以在它的属性props中包含其他元素(译注:用于形成元素树)。创建一个React元素element成本很低。元素element创建之后是不可变的。
● 组件:一个组件component可以通过多种方式声明。可以是带有一个render()方法的类,简单点也可以定义为一个函数。这两种情况下,它都把属性props作为输入,把返回的一棵元素树作为输出。
● 实例:一个实例instance是你在所写的组件类component class中使用关键字this所指向的东西(译注:组件实例)。它用来存储本地状态和响应生命周期事件很有用。
函数式组件(Functional component)根本没有实例instance。类组件(Class component)有实例instance,但是永远也不需要直接创建一个组件的实例,因为React帮我们做了这些。
如何有条件地向React组件添加属性?
对于某些属性,React非常聪明,如果传递给它的值是虚值,可以省略该属性。
var InputComponent = React.createClass({
render: function() {
var required = true;
var disabled = false;
return(
)
}
})
渲染结果:
另一种可能的方法是:
var condition = true;
var component = (
有状态组件、无状态组件
区分有状态和无状态组件?
有状态组件 无状态组件
1、在内存中存储有关组件状态变化的信息 1、计算组件的内部的状态
2、有权改变状态 2、无权改变状态
3、包含过去、现在和未来可能的状态变化情况 3、不包含过去、现在和未来可能的状态变化情况
4、接收无状态组件状态变化要求的通知,然后将props发送给他们 4、从有状态组件接收props并将其视为回调函数
对有状态组件和无状态组件的理解及使用场景
一、有状态组件
1、特点:
● 是类组件
● 有继承
● 可以使用this
● 可以使用react的生命周期
● 使用较多,容易频繁触发生命周期钩子函数,影响性能
● 内部使用 state,维护自身状态的变化,有状态组件根据外部组件传入的 props 和自身的 state进行渲染。
2、使用场景:
● 需要使用到状态的。
● 需要使用状态操作组件的(无状态组件的也可以实现新版本react hooks也可实现)
3、总结:
类组件可以维护自身的状态变量,即组件的 state ,类组件还有不同的生命周期方法,可以让开发者能够在组件的不同阶段(挂载、更新、卸载),对组件做更多的控制。类组件则既可以充当无状态组件,也可以充当有状态组件。当一个类组件不需要管理自身状态时,也可称为无状态组件。
二、无状态组件
1、特点:
● 不依赖自身的状态state
● 可以是类组件或者函数组件。
● 可以完全避免使用 this 关键字。(由于使用的是箭头函数事件无需绑定)
● 有更高的性能。当不需要使用生命周期钩子时,应该首先使用无状态函数组件
● 组件内部不维护 state ,只根据外部组件传入的 props 进行渲染的组件,当 props 改变时,组件重新渲染。
2、使用场景:
● 组件不需要管理 state,纯展示
3、优点:
● 简化代码、专注于 render
● 组件不需要被实例化,无生命周期,提升性能。输出(渲染)只取决于输入(属性),无副作用
● 视图和数据的解耦分离
4、缺点:
● 无法使用 ref
● 无生命周期方法
● 无法控制组件的重渲染,因为无法使用shouldComponentUpdate 方法,当组件接受到新的属性时则会重渲染
三、总结:
组件内部状态且与外部无关的组件,可以考虑用状态组件,这样状态树就不会过于复杂,易于理解和管理。当一个组件不需要管理自身状态时,也就是无状态组件,应该优先设计为函数组件。比如自定义的 、 等组件。
函数组件、类组件
函数组件(Functional component,也称哑组件,或展示组件,或hooks组件)和类组件(Class component)的相同点和不同点?(税友)
一、相同点:都可以接收props返回react元素
二、不同点:
● 编程思想:类组件需要创建实例,面向对象,函数组件不需要创建实例,接收输入,返回输出,函数式编程
● 内存占用:类组建需要创建并保存实例,占用一定的内存
● 值捕获特性:函数组件具有值捕获的特性 。function组件能捕获渲染的值(captaure the rendered values),读取渲染闭包内的数据,而class组件在react通过this.的方式读取,this是可变的,所以总能获取最新的props
● 状态:类组件有自己的状态,函数组件没有,只能通过useState。Class把state属性挂载的对象保存到memoizedState属性中,而Function是用链表来保存状态的,memoizedState属性保存是链表的头指针。
● 生命周期:类组件有完整生命周期,函数组件没有,可以使用useEffect实现类似的生命周期
● 可测试性:函数组件方便测试
● 逻辑复用:类组件继承 Hoc(逻辑混乱 嵌套),组合优于继承,函数组件hook逻辑复用
● 跳过更新:shouldComponentUpdate PureComponent,React.memo
● 发展未来:函数组件将成为主流,屏蔽this、规范、复用,适合时间分片和渲染
类组件
为什么类方法需要绑定到类实例?
在JS中,this值会根据当前上下文变化。
在React类组件方法中,开发人员通常希望this引用组件的当前实例。因此有必要将这些方法绑定到实例。
通常,这是在构造函数中完成的。
在构造函数中调用super的目的是什么?/ 在构造函数调用super并将props作为参数传入的作用是啥?
在调用super()方法之前,子类构造函数无法使用this引用,子类必须在 constructor 中调用 super()。将props参数传递给super()调用的主要原因是在子构造函数中能够在constructor通过this.props来获取传入的props
● 传递props
class MyComponent extends React.Component {
constructor(props) {
super(props);
console.log(this.props); // { name: ‘sudheer’, age: 30 }
}
}
● 没传递props
class MyComponent extends React.Component {
constructor(props) {
super();
console.log(this.props); // undefined
// 但是Props参数仍然可用
console.log(props); // Prints { name: ‘sudheer’, age: 30 }
}
render() {
// 构造函数外部不受影响
console.log(this.props); // { name: ‘sudheer’, age: 30 }
}
}
渲染组件
UI组件、容器组件
展示组件(Presentational component)和容器组件(Container component)之间有何不同?
根据组件的职责通常把组件分为 UI 组件和容器组件。
UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。
两者通过 React-Redux 提供 connect 方法联系起来。
受控组件、非受控组件
何为受控组件(controlled component)?
React负责渲染表单的组件,值是来自于state控制的输入表单元素称为受控组件
你对受控组件和非受控组件了解多少? / 什么是受控组件? 什么是非受控组件?
● 受控组件是React控制中的组件,并且是表单数据真实的唯一来源。
● 非受控组件是由DOM处理表单数据的地方,而不是在React组件中。
尽管非受控组件通常更易于实现,因为只需使用refs即可从DOM中获取值,但通常建议优先选择受控制的组件,而不是非受控制的组件。
这样做的主要原因是受控组件支持即时字段验证,允许有条件地禁用/启用按钮,强制输入格式。
受控组件 非受控组件
1、没有维持自己的状态 1、保持着自己的状态
2、数据由父组件控制 2、数据由dom控制
3、通过props获取当前值,然后通过回调通知更改 3、refs用于获取当前值
props
区分状态(state)和 属性(props)?/ (组件的)状态(state)和属性(props)之间有何不同?
● Props是一个从外部传进组件的参数,主要作用就是父组件向子组件传递数据,但是props对于使用它的组件来说是只读的,一旦赋值不能修改,只能通过外部组件主动传入新的props来重新渲染子组件
● State 一个组件的显示形态可以由数据状态和外部参数决定,外部参数是props,数据状态就是state,首先,在组件初始化的时候,用this.state给组件设定一个初始的state,在第一次渲染的时候就会用这个数据来渲染组件,state不同于props一点是,state可以修改,通过this.setState()方法来修改state
条件 state props
从父组件中接收初始值 yes yes
从父组件可以改变值 no yes
在组件中设置默认值 yes yes
在组件的内部变化 yes no
设置子组件的初始值 yes yes
在子组件的内部更改 no yes
纯函数
什么是纯函数?
纯函数是不依赖并且不会在其作用域之外修改变量状态的函数。本质上,纯函数始终在给定相同参数的情况下返回相同结果。
state
React中的状态是什么?它是如何使用的?
状态是 React 组件的核心,是数据的来源,必须尽可能简单。基本上状态是确定组件呈现和行为的对象。与props 不同,它们是可变的,并创建动态和交互式组件。可以通过 this.state() 访问它们。
如何更新组件的状态
this.setState()、useState
当调用setState时,React render是如何工作的?
可以将render分为两个步骤
● 虚拟DOM渲染:当render方法被调用时,它返回一个新的组件的虚拟DOM结构。当调用setState()时,render会被再次调用,因为默认情况下shouldComponentUpdate总是返回true,所以默认情况下React是没有优化的。
● 原生DOM渲染:React只会在虚拟DOM中修改真实DOM节点,而且修改的次数非常少——这是很棒的React特性,它优化了真实DOM的变化,使React变得更快。
setState
调用 setState 之后发生了什么?
React在调用setstate后,react会将传入的参数对象和组件当前的状态合并,触发调和过程,
在调和过程中,react会根据新的状态构建react元素树重新渲染整个UI界面,在得到元素树之后,react会自动计算新老节点的差异,根据差异对界面进行最小化重新渲染
setState是同步的还是异步的?
一、setState 并不是单纯同步/异步的,它的表现会因调用场景的不同而不同:
● 在 React 钩子函数及合成事件中,它表现为异步;
● 同步:
○ DOM 原生事件中(绕过React通过addEventListener直接添加的事件处理函数)
○ 通过setTimeout/setInterval产生的异步调用
二、这种差异,本质上是由 React 事务机制和批量更新机制的工作方式来决定的:在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。
为什么建议传递给 setState 的参数是一个 callback 而不是一个对象
因为在setstate中,props和state可能会异步更新,也就是说,对相同的变量进行处理的时候,会将这多次处理合并为一个,这个是批处理;而如果传入函数,那么会进行链式调用,这个函数会被react加入到一个执行队列中,函数中的代码会依次执行。
Refs
React 中 refs 的作用是什么?
Refs提供了一种访问在render方法中创建的 DOM 节点或者 React 元素的方法。在典型的数据流中,props是父子组件交互的唯一方式,想要修改子组件,需要使用新的pros重新渲染它。凡事有例外,某些情况下需要在典型数据流外,强制修改子代,这个时候可以使用Refs
class CustomForm extends Component {
handleSubmit = () => {
console.log("Input Value: ", this.input.value)
}
render () {
return (
type=‘text’
ref={(input) => this.input = input} />
Submit
)
}
}
上述代码中的 input 域包含了一个 ref 属性,该属性声明的回调函数会接收 input 对应的 DOM 元素,我们将其绑定到 this 指针以便在其他的类函数中使用。
● refs 并不是类组件的专属,函数式组件同样能够利用闭包暂存其值:
function CustomForm ({handleSubmit}) {
let inputElement
return (