一、什么是React?为什么会出现React这样的框架?
1.React是一个用于构建用户界面的JavaScript库。
2.React是Facebook开发的一款JS库,Faccbook认为MVC不适合大规模的应用,当系统中有很多模型和相应的试图时,其复杂程度就会迅速扩大,导致难以理解及调试,特别是模型和视图可能存在双向数据流动。解决方法通过Flux和React。React官网关于React还可以了解到以下四点:
①React不是一个MVC框架。
②React不使用模板。
③响应式更新非常简单。
④HTML5仅仅是一个开始。
二、什么是Flux和React?
1.Flux是一个系统框架,用于推进应用中的数据单向流动。
2.React是一个JavaScript框架,用于构建“可预测的”和声明式的“Web用户界面”。
三、React的特点是什么?
1.声明式设计---React采用声明范式,可以轻松描述应用。
2.高效---React通过对DOM的模拟,最大限度地减少与DOM的交互。
3.灵活---React可以与一致的库或框架很好地配合。
4.JSX---JSX是JavaScript语法的扩展。(React开发不一定使用JSX,但是建议使用)
5.组件---通过React构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
6.单项响应数据流---React实现了单项响应数据流,从而减少了重复代码,这也是它比传统数据绑定更简单的原因。
四、React主要原理是什么?
1.Virtual DOM(虚拟DOM):Virtual DOM实际上是JS对象,使用React之后我们不直接和DOM API打交道,我们直接访问JS对象比访问DOM API高效的多。我们通过Virtual DOM去更新真实的DOM,由这个Virtual DOM管理真实DOM的更新。
2.Diff算法:在React中,Diff算法需要与Virtual DOM配合。React会使用Diff算法计算出Virtual DOM中真正发生变化的部分,并且只会针对该部分进行DOM操作,从而避免了对页面进行大面积的更新渲染,减小性能的开销。更新Virtual DOM并不保证马上影响真实的DOM,React会等到时间循环结束利用Diff算法,这也是为什么通过多一层的Virtual DOM操作会更快的原因,通过当前新的DOM表述与之前旧的DOM 作比较,计算出最小的步骤更新DOM。
3.Components组件:Virtual DOM的节点被称为component,它是一个完整抽象的组件,由components构成。components的存在让计算DOM Diff更高效。
注意:原生HTML元素名以小写字母开头,而自定义的React类名以大写字母开头。除此之外还需要注意组件类只能包含一个顶层标签,否则也会报错。
五、在React中元素(element)和组件(component)有什么区别?
1.在React中元素(虚拟DOM)是页面中DOM元素的对象表示方式。
2.在React中组建是一个函数或一个类,它可以接收输入并返回一个元素。
注意:在工作中为了提高开发效率,通常使用JSX语法表示React元素(虚拟DOM)。
六、什么是React的refs?为什么他很重要?
1.refs允许你直接访问DOM元素或组件的实例。使用时,向组件添加个ref属性。
2.如果该属性值是一个回调函数,它将接受底层的DOM元素或组件的已挂载实例作为第一个参数,可以在组件中存储它。
export class App extends Component {
showResult() {
console.log(this.input.value)
}
render() {
return (
<div>
<input type="text" ref={input => { this.input = input }/>
<button onClick={this.showResult.bind(this)}>展示结果</button>
</div>
)
}
}
注意:如果属性值是一个字符串,React将会在组件实例化对象的refs属性中,存储一个同名的属性,该属性是对这个DOM元素的引用。可以通过原生的DOM API操作它。
export class App extends Component {
showResult() {
console.log(this.refs.username.value)
}
render() {
return (
<div>
<input type="text" ref="username"/>
<button onClick={this.showResult.bind(this)}>展示结果</button>
</div>
)
}
}
七、Vue和React的共同点和区别是什么?
1.共同点:
①都使用了虚拟DOM。
②都提供了响应式和组件化的视图组件。
③都有全局状态管理的库。(vue-router、vuex、react-router、redux等)
2.区别:
①Vue是双向绑定,采用template;React是单项的,采用jsx。
②性能方面:当组件的状态发生变化时,React的机制会触发整个组件树的重新渲染,Vue提供了优化的重新渲染,其中系统在渲染过程中跟踪依赖关系并相应地工作。
八、React Diff原理
1.把树形结构按照层次分解,只比较同级元素。
2.给列表结构的每个单元添加唯一的key属性,方便比较。
3.React只会匹配相同class的component(class指的是组件的名字)
4.合并操作,调用component的setState方法的时候,React将其标记为dirty到每一个事件循环,React检查所有标记dirty的component重新绘制。
5.选择性子树渲染。开发人员可以重写shouldComponentUpdate提高Diff的性能。
九、React中的组件传参。
1.父传子:将父组件中的属性传入子组件,子组件可以用props直接接受并使用。
2.子传父:子组件调用父组件中传来的方法来改变父组件中的值。
3.兄弟间:找到二者共同的父节点,结合上面两种方式由父节点转发信息进行通信。
4.跨层级:使用context上下文,通过使用context.Provider数据提供者来实现全局的数据共享。
5.发布订阅模式:通过引入event模块进行通信。
6.全局状态管理工具:借助Redux或者Mobx等全局状态管理工具进行通信。
十、React中class定义的组件生命周期钩子函数(初始化阶段、运行中阶段、销毁阶段)
1.初始化阶段
①设置组件的初始化状态:constructor()
②组件在挂载之前触发,这时可向开启定时器或向服务器发送请求:componentWillMount()
③组件渲染:render()
④组件渲染完毕,此时可执行DOM的相关操作:componentDidMount()
2.运行中阶段
①组件接收到新的属性时触发:componentWillReceiveProps()
②组件接收新属性或组件状态发生改变时触发(首次渲染不触发):shouldComponentUpdate()
③组件更新前触发:componentWilllUpdate()
④组件更新完毕,页面产生新的DOM,可进行DOM操作:componentDidUpdate()
3.销毁阶段
组件销毁前触发,可做清理操作(清除定时器):componentWillUnMount()
十一、React中Hooks是如何模拟组件的生命周期的?
1.componentDidMount
function Example() {
useEffect(() => console.log('mounted'),[]);
return null;
}
2.componentDidUpdate
function Example() {
useEffect(() => console.log('count update'),[count]);
return null;
}
3.componentWillUnmount
function Example() {
useEffect(() => {
return () => {
console.log('will unmount');
}
},[]);
}
十二、React中class定义的组件和function定义的组件的区别?
1.function定义的组件没有this指向的问题。
2.class定义的组件有自己的局部状态(this.state)和自己的生命周期函数。
3.function定义的组件是无状态组件,在16.8之后可以用Hooks(useEffect)来模拟组件的局部状态和生命周期。
十三、谈谈你对React中的高级组件的了解。
1.高阶组件就是一个没有副作用的纯函数。
2.高阶组件是把一个组件当做参数,返回值作为新组件的函数。
3.高阶组件实际上就是高阶函数,如map、forEach。
4.常用的高阶组件:withRouter(路由中的),connect(reduct-redux中的)。
十四、Redux的理解。
1.Redux是一个全局状态管理插件,用来操作数据的,可以结合任何一个js库来使用。
2.Redux是单向数据流,view通过dispatch来派发一个action改变数据,数据改变之后,页面重新渲染。
3.Redux分为三部分:state用来存储数据,所有的数据改变都在reducer中进行,redux中还有一个action,用来组织数据。
十五、Redux遵循的三原则
1.单一事件来源:整个应用的状态存储在单个store中的对象/状态树里。
注:单一状态树可以更容易地跟随时间变换,并调试和检查程序。
2.状态是只读的:改变状态的唯一方法是去触发一个动作。
3.使用纯函数进行更改:指定状态树如何通过操作进行转换。
注:纯函数指返回值仅取决于其参数值的函数。
十六、Redux组件组成
1.View—只显示Store提供的数据
2.Store—整个程序的状态/对象树保存在Store中。
注:Store是一个JS对象,它可以保存程序的状态,并提供方法来访问状态、调度操作和注册侦听器。我们可以将中间件传递到Store来处理数据,并记录改变存储状态的各种操作。所有操作都通过Reducer返回一个新状态。
3.Reducer—确定状态如何变化。
注:Reducers是纯函数,他规定应用程序的状态怎样因响应Action改变。Reducers通过接受先前的状态和Action来工作,然后返回一个新状态。根据操作类型确定需要执行哪种更新,然后返回新的值。若不需要完成任务,返回原来的状态。
4.Action—用来描述发生什么的事情的对象
注:Action必须有type属性,该属性是指示正在执行的Action的类型。必须将它们定义为字符串常量,并且还可以向其添加更多的属性。
function addTodo(text) {
return {
type:ADD_TODO,
text
}
}
十七、Redux的优点是什么?
1.结果的可预测性—存在真实来源Store
2.可维护性—具有可预测的结果和严格的结构
3.服务器端渲染—优化应用性能,对初渲染友好,从而提供更好的用户体验
4.开发人员工具—从操作到状态更改,开发人员可以实时跟踪应用中发生的所有事情
5.易于测试—Redux的代码主要小巧、纯粹和独立的功能
6.组织—Redux准确的说明了代码的组织方式
7.社区和生态系统——Redux背后有一个巨大的社区
十八、React中的错误边界
1.React16.X中引入了错误边界(Error Boundaries)概念。
2.以React组件的形式实现,可以捕获它的子组件中产生的错误,类似于try-catch。
3.有了错误边界,即使某个组件有错误,整个程序仍然完全正常运行,只有出错的组件会显示一个后备界面。
4.只有类组件才可以成为错误边界。componentDidcatch()函数使用方法与JS中catch{}代码块类似,但只能用于组件。
5.componentDidcatch()函数内部将hasError状态设置为true:如果出错状态为true,就渲染后备界面;如果是false就是将想渲染的React组件界面当做子组件界面渲染出来。
6.无法捕获的错误Error Boundaries:
①事件错误。
②Error Boundaries本身错误。
③异步代码。
十九、对React router的理解
1.React路由是构建在React之上的强大路由库,有助于向应用程序添加新的屏幕和流,使URL与网页上显示的数据保持同步,用于开发单页面Web页面。
2.React Router的优点:
①在React Router v4中,API是'All About Components'。可以将 Router 可视化为单个根组件其中我们将特定的子路由()包起来。
②无需手动设置历史值:在 React Router v4 中,我们要做的就是将路由包装在 组件中。
③包是分开的:共有三个包,分别用于 Web、Native 和 Core,基于类似的编码风格很容易进行切换。
3.当想要仅显示要在多个定义的路线中呈现的单个路线时,可以使用'switch'关键字。其会按顺序将已定义的URL与已定义的路由进行匹配。找到第一个匹配项后,渲染指定路径,从而绕过其他路线。
<switch>
<route exact="" path="'/'" component="{Home}/">
<route path="'/posts/:id'" component="{Newpost}/">
<route path="'/posts'" component="{Post}/">
</route></route></route></switch>
二十、React中react-router和react-router-dom的区别
1.API
①React-router:提供了路由的核心API。如Router、Route、Switch等,但没有提供有关DOM操作进行路由跳转的API。
②React-router-dom:提供了BrowserRouter、Route、Link等API,可以通过DOM操作触发事件控制路由。
Link组件:渲染一个a标签。
BrowserRouter组件:使用pushState和popState时间构建路由。
HashRouter组件:使用hash和hashchange事件构建路由。
2.动态路由跳转
①React-router:(router4.0以上) this.props.history.push('/path')
(router3.0以上) this.props.router.push('/path')
②React-router-dom:this.props.history.push('/path')
3.使用区别
①React-router-dom:在React-router的基础上扩展了可操作DOM的API。
②直接npm安装react-router-dom,可使用react-router的API。
③Swith和Route都是从react-router中导入了相应的组件并重新导出。
import { Switch, Route, Router } from 'react-router';
import { Switch, Route, BrowserRouter, HashHistory, Link } from 'react-router-dom';
二十一、Hooks的优缺点
1.优点
①更容易复用代码
②清爽的代码风格:函数式编程风格,函数式组件、状态保存在运行环境、每个功能都包裹在函数中,整体风格更优雅、清爽。
③代码量更少:props或状态取值更方便,从父级作用域直接取。更改状态也变得更加简单。
④更容易发现无用的状态和函数。
⑤更容易拆分组件
2.缺点:
①部分代码从主动变成响应式
②状态不同步
二十二、React常用的Hooks,及使用场景
1.useState:使用useState来定义函数组件的状态
①引入
②接受一个参数作为初始值
③返回一个数组,第一个值为状态,第二个值为改变状态的函数
2.useEffect(副作用Hooks):给没有生命周期的组件,添加结束渲染的信号。在渲染结束之后执行。
①第一个参数,接受一个函数作为参数
②第二个参数,接受[依赖列表],只有依赖更新时,才会执行函数
注:①如果不接受第二个参数,那么每次更新渲染页面都会调用useEffect的回调函数
②如果第二个参数传入一个数组,这个数组表示在更新执行所依赖的列表,只有依赖列表改变时,才会触发回调函数。
③如果第二个参数传入一个空数组[ ],useEffect只运行一次,以获取页面的初始数据
③返回一个函数,先执行返回函数,在执行参数函数
注:副作用是指数据获取,数据订阅,以及手动更改React组件中的DOM
3.useLayoutEffect:在DOM更新完成之后执行某个操作(有DOM操作的副作用Hooks)
注:useLayoutEffect会比useEffect先执行
4.useMemo:组件中的函数跟随状态更新(优化函数组件的功能函数)
①接受一个函数作为参数
②同样接受第二个参数作为依赖列表(对比useEffect、useLayoutEffect)
③返回一个值。(返回值类型不限)
5.useCallback:让某些操作、方法跟随状态的更新去执行。返回一个函数。(对比useMemo学习)
6.useRef:用于长久的保存数据,返回一个子元素索引。
注:保存的对象发生改变,不通知,属性变更不会重新渲染。
7.useContext:子组件之间共享父组件传入状态。
二十三、Real DOM和Virtual DOM的区别
Real DOM(真实DOM) | Virtual DOM(虚拟DOM) |
---|---|
1.更新缓慢。 | 1.更新更快。 |
2.可以直接更新HTML。 | 2.无法直接更新HTML。 |
3.元素更新,创建新DOM。 | 3.元素更新,更新JSX。 |
4.DOM操作代价高。 | 4.DOM操作简单。 |
5.消耗内存多。 | 5.很少的内存消耗。 |