1、React 事件绑定原理
理解:react中的事件都是合成事件,不是把每一个dom的事件绑定在dom上,而是把事件统一绑定到document中,触发时通过事件冒泡到document进行触发合成事件,因为是合成事件,所以我们无法去使用e.stopPropagation去阻止,而是使用e.preventDefault去阻止。
1.事件注册:组件更新或者装载时,在给dom增加合成事件时,需要将增加的target传入到document进行判断,给document注册原生事件回调为dispatchEvent(统一的事件分发机制)。
2.事件存储:EventPluginHub负责管理React合成事件的callback,它将callback存储到listennerBank中,另外还存储了负责合成事件的Plugin,Event存储到listennerbank中,每一个元素在listennerBank中会有唯一的key。
3.事件触发执行:点击时冒泡到docunment中,触发注册原生事件的回调dispatchEvent,获取到触发这个事件的最深层元素,事件执行利用react的批处理机制。
案例
csharp
<div onClick={this.parentClick} ref={ref => this.parent = ref}>
<div onClick={this.childClick} ref={ref => this.child = ref}>
test
</div>
</div>
点击test后
1.首先获取到this.child
2.遍历此元素的所有父元素,依次对每一级元素进行处理
3.构成合成事件
4.将每一级的合成事件存储在eventQueen事件队列中
5.遍历,是否组织冒泡,是则停止,否则继续
6.释放已经完成的事件
4.合成事件:循环所有类型的eventPlugin,对应每个事件类型,生成不同的事件池,如果是空,则生成新的,有则用之前的,根据唯一key获取到指定的回调函数,再返回带有参数的回调函数。
5.总流程:组件装载/更新 -- 新增/删除事件 -- eventplugin添加到ListennerBank中监听事件 -- 触发事件 -- 生成合成事件 -- 通过唯一key获取到指定函数 -- 执行指定回调函数 -- 执行完毕后释放
2、什么是React?
- React 是 Facebook 在 2011 年开发的前端 JavaScript 库。
- 它遵循基于组件的方法,有助于构建可重用的UI组件。
- 它用于开发复杂和交互式的 Web 和移动 UI。
- 尽管它仅在 2015 年开源,但有一个很大的支持社区。
3、 React有什么特点?
React的主要功能如下:
- 它使用**虚拟DOM **而不是真正的DOM。
- 它可以用服务器端渲染。
- 它遵循单向数据流或数据绑定。
4、类组件和函数组件的区别
定义组件有两个要求:
- 组件名称必须以大写字母开头
- 组件的返回值只能有一个根元素
函数组件
js
function Welcome (props) {
return <h1>Welcome {props.name}</h1>
}
ReactDOM.render(<Welcome name='react' />, document.getElementById('root'));
- 函数组件接收一个单一的
props
对象并返回了一个React元素
类组件
js
class Welcome extends React.Component {
render() {
return (
<h1>Welcome { this.props.name }</h1>
);
}
}
ReactDOM.render(<Welcome name='react' />, document.getElementById('root'));
- 无论是使用函数或是类来声明一个组件,它决不能修改它自己的
props
。 - 所有 React 组件都必须是纯函数,并禁止修改其自身
props
。 - React是单项数据流,父组件改变了属性,那么子组件视图会更新。
- 属性
props
是外界传递过来的,状态state
是组件本身的,状态可以在组件中任意修改 - 组件的属性和状态改变都会更新视图。
区别
函数组件和类组件当然是有区别的,而且函数组件的性能比类组件的性能要高,因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。
区别 | 函数组件 | 类组件 |
---|---|---|
是否有 this |
没有 | 有 |
是否有生命周期 | 没有 | 有 |
是否有状态 state |
没有 | 有 |
。
5、请你说说React的路由是什么
1.1、基本用法
单页面得特点:只需要加载一次主页面,通过局部刷新,就可以实现跳转或者切换页面
优点:加载速度快,用户体验比较好
缺点:
-
第一次加载比传统要慢一点
-
不利seo
-
页面相对复杂
-
返回键
1.2安装react-router-dom
cnpm install react-router-dom
下载到生产环境的依赖中。
在组件中通过对象的解构方式去获取到react-router-dom
内置组件,在组件中,按需引入内置组件,在页面中进行使用:
-
HashRouter表示一个路由的根容器,将来所有的路由相关的东西,都要包裹在HashRouter里面,而且一个网站中,只需要使用一次HashRouter就好了;
-
Route表示一个路由规则,在Route上,有两个比较重要的属性,path,component
-
Link表示一个路由的链接
代码示例
render(){`` ``return` `(`` ``<HashRouter>`` ``<div>`` ``<h1>这是网站的根目录</h1>`` ``<hr />`` ``<Link to=``"/home"``>首页</Link> `` ``<Link to=``"/movie/"``>电影</Link> `` ``<Link to=``"/about"``>关于</Link>`` ``<hr />`` ``<Route path=``"/home"` `component={Home} ></Route><hr/>`` ``<Route path=``"/movie"` `component={Movie} exact></Route><hr/>`` ``<Route path=``"/about"` `component={About}></Route><hr/>`` ``</div>`` ``</HashRouter>`` ``);`` ``}
当使用HashRouter把APP根组件的元素包裹起来之后,网站就已经启用路由了,在一个HashRouter中,只能有唯一的一个根元素。 在一个网站中,只需要使用唯一的一次<HashRouter></HashRouter>
就行了。
Route创建的标签,就是路由规则,其中path表示要匹配的路由,component表示要展示的组件。Route具有两种身份:1.它是一个路由匹配规则;2.它是一个占位符,表示将来匹配到的组件都放到这个位置
需要注意的地方
-
Route 组件path地址是以/开头 ,配置component属性,是显示的组件,这个属性不可以大写
-
Route组件可以单双标签使用,单标签需要/结尾,双标签不可以在中间写入别的东西
-
Link to属性的地址也是/开头,Link在页面渲染的是a标签
2.1、路由传值
通过配置路由的地址,在Link跳转时
-
Route path路径后面 /:id (key)
-
Link to 路径后面 /top/10 (value)
接收传值:
-
class类组件,this.props.match.params.属性名
-
函数组件:形参.match.params.属性名
代码示例
render(){`` ``return` `(`` ``<HashRouter>`` ``<div>`` ``<h1>这是网站的根目录</h1>`` ``<hr />`` ``<Link to=``"/movie/top/10"``>电影</Link> `` ``<hr />`` ``<Route path=``"/movie/:type/:id"` `component={Movie} exact></Route>`` ``</div>`` ``</HashRouter>`` ``);`` ``}
在Route内置组件中,配置path地址:
<Route path=``"/movie/:type/:id"` `component={Movie} exact></Route>
在Link内置组件中,配置to属性,进行跳转:
<Link to=``"/movie/top/10"``>电影</Link>
类组件中通过生命周期进行接收,this.props携带路由传递过来的数据:
render(){`` ``console.log(``this``);`` ``return` `(`` ``<div>`` ``电影--{``this``.props.match.``params``.type}--{``this``.props.match.``params``.id}`` ``</div>`` ``);`` ``}
代码优化后:
class` `Movie extends React.Component{` ` ``constructor(props){`` ``super();`` ``this``.state = {`` ``routeParams:props.match.``params`` ``}`` ``}` ` ``render(){`` ``console.log(``this``);`` ``return` `(`` ``<div>`` ``电影--{``this``.state.routeParams.type}--{``this``.state.routeParams.id}`` ``</div>`` ``);`` ``}``}
函数组件中通过形参接收传递过来的值,props形参,函数组件作为路由组件,props就是传递过来的对象,里面携带着路由传递过来的数据
import React ``from` `'react'` `export ``default` `function home(props) {`` ``return` `(`` ``<div>`` ``{props.match.``params``.id}`` ``</div>`` ``)``}
2.2、嵌套路由
嵌套路由:在路由组件中,使用Link, Route,配置子路由,实现跳转,切换;
下面为一级路由,在一级路由Home为路由组件
<Route path=``"/home"` `component={ Home }></Route>
在Home组件中继续使用Link,Route进行路由的嵌套,需要注意的就是路由地址,前部分为一级路由地址,后面接一个二级路由相应的路径
render() {`` ``return` `(`` ``<div>`` ``<ul>`` ``<li><Link to=``"/home/a"``>推荐</Link></li>`` ``<li><Link to=``"/home/b"``>新时代</Link></li>`` ``<li><Link to=``"/home/c"``>动漫</Link></li>`` ``</ul>`` ``<Route path=``"/home/a"` `component={ A }></Route>`` ``<Route path=``"/home/b"` `component={ B }></Route>`` ``<Route path=``"/home/c"` `component={ C }></Route>`` ``</div>`` ``)``}
2.3、JS实现路由跳转
引入BrowserRouter模块
import {BrowserRouter,HashRouter,Route,Link} ``from` `'react-router-dom'
使用BrowserRouter作为根容器
jump(){`` ``window.location.href = ``"/news"``}` `render(){`` ``return` `(`` ``<BrowserRouter>`` ``<div>`` ``<h1>这是网站的根目录</h1>`` ``<hr />`` ``<button onClick={()=>{``this``.jump()}}>新闻</button>`` ``<hr />`` ``<Route path=``"/news"` `component={News}></Route>`` ``</div>`` ``</BrowserRouter>`` ``);``}
在render方法中,写一个按钮,按钮名称为js跳转路由,定义一个onClick方法,箭头函数解决this指向问题,与render同级,定义一个jump方法,在jump方法中执行一句代码进行路由跳转,使用window.location.href = "路由的地址"实现路由跳转。
3、react-router-dom内置组件
首先按需引入,使用什么内置组件,就需要引入
import { BrowserRouter, Link, Route,Redirect,NavLink,Switch } ``from` `'react-router-dom'
3.1、在组件中使用NavLink
NavLink 带有选中activeClassName ,如果路由处于激活状态,显示激活class样式。
在我们之前案例的基础上,找到Link组件,我们已经学到Link组件的作用,可以进行路由的跳转,通过to属性,跳转相应的path地址。
```html``//``<ul>`` ``<li>`` ``<Link to=``"/home"``>首页</Link>`` ``</li>`` ``<li>`` ``<Link to=``"/video"``>好看视频</Link>`` ``</li>``</ul>
将组件中的Link全部换成NavLink组件
```html//
-
"red"` `to=
"/home">首页</NavLink>
-
<li>
<NavLink activeClassName=
"red"` `to="/video"
>好看视频````````我们会发现,之前可以正常进行路由跳转,换成NavLink,还依然可以正常跳转,证明组件得跳转使用NavLink也可以实现,那么问题来了,NavLink有什么用,为什么封装了NavLink,将每一个NavLink加入一个activeClassName属性绑定一个class类样式,这时在触发NavLink时,会触发相应得样式,这样有一个切换效果。
3.2、在组件中使用Redirect内置组件
Redirect 重定向 具备to属性,可以直接跳转到指定路由。
在render方法中,使用内置组件,Redirect内置组件使用to属性,当执行到内置标签是,会进行to跳转路由,to后面接的地址是什么,就可以匹配到相应得路由组件。
```html``//``<Redirect to=``"/home/c"``></Redirect>
6、列出React的一些主要优点。
React的一些主要优点是:
- 它提高了应用的性能
- 可以方便地在客户端和服务器端使用
- 由于 JSX,代码的可读性很好
- React 很容易与 Meteor,Angular 等其他框架集成
- 使用React,编写UI测试用例变得非常容易
7、React hooks用过吗,为什么要用
函数组件比起类组件"少"了很多东西,比如生命周期、对 state 的管理等。这就给函数组件的使用带来了非常多的局限性。
React-Hooks 的出现,就是为了帮助函数组件补齐这些(相对于类组件来说)缺失的能力
8虚拟DOM的优劣如何
- 保证性能下限: 框架的虚拟 DOM 需要适配任何上层 API 可能产生的操作,它的一些 DOM 操作的实现必须是普适的,所以它的性能并不是最优的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虚拟 DOM 至少可以保证在你不需要手动优化的情况下,依然可以提供还不错的性能,即保证性能的下限;
- 无需手动操作 DOM: 我们不再需要手动去操作 DOM,只需要写好 View-Model 的代码逻辑,框架会根据虚拟 DOM 和 数据双向绑定,帮我们以可预期的方式更新视图,极大提高我们的开发效率;
- 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染、weex 开发等等。
缺点:
- 无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。
首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。
9、React有哪些限制?
React的限制如下:
- React 只是一个库,而不是一个完整的框架
- 它的库非常庞大,需要时间来理解
- 新手程序员可能很难理解
- 编码变得复杂,因为它使用内联模板和 JSX
10、什么是JSX?
JSX 是J avaScript XML 的简写。是 React 使用的一种文件,它利用 JavaScript 的表现力和类似 HTML 的模板语法。这使得 HTML 文件非常容易理解。此文件能使应用非常可靠,并能够提高其性能。下面是JSX的一个例子:
javascriptrender(){ return( <div> <h1> Hello World from Edureka!!</h1> </div> ); }
11、react中不同组件之间如何做到数据交互?
- 父组件向子组件通信:使用 props
- 子组件向父组件通信:使用 props 回调
- 跨级组件间通信:使用 context 对象
- 非嵌套组件间通信:使用事件订阅
事实上,在组件间进行通信时,这些通信方式都可以使用,区别只在于使用相应的通信方式的复杂程度和个人喜好,选择最合适的那一个。比如,通过事件订阅模式通信不止可以应用在非嵌套组件间,还可以用于跨级组件间,非嵌套组件间通信也可以使用 context 等。关键是选择最合适的方式。
当然,自己实现组件间的通信还是太难以管理了,因此出现了很多状态管理工具,如 flux、redux 等,使用这些工具使得组件间的通信更容易追踪和管理。
12、react中refs的作用是什么?
Refs
是React
提供给我们的安全访问DOM
元素或者某个组件实例的句柄- 可以为元素添加
ref
属性然后在回调函数中接受该元素在DOM
树中的句柄,该值会作为回调函数的第一个参数返回
13、请列举react生命周期函数。
React 生命周期分为三种状态 1. 初始化 2.更新 3.销毁
- 初始化
1、getDefaultProps()
设置默认的props,也可以用dufaultProps设置组件的默认属性.
2、getInitialState()
在使用es6的class语法时是没有这个钩子函数的,可以直接在constructor中定义this.state。此时可以访问this.props
3、componentWillMount()
组件初始化时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改state。
在渲染前调用,在客户端也在服务端。
4、 render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行。此时就不能更改state了。
5、componentDidMount()
组件渲染之后调用,只调用一次。
在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过**this****.getDOMNode()**来进行访问。
如果你想和其他JavaScript框架一起使用,可以在这个方法中调用****setTimeout, setInterval或者发送****AJAX请求等操作(防止异步操作阻塞UI)。
- 更新
6、componentWillReceiveProps(nextProps)
组件初始化时不调用,组件接受新的props时调用。
*使用componentWillReceiveProps的时候,不要去向上分发,调用父组件的相关setState方法,否则会成为死循环*
*在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。*
7、shouldComponentUpdate(nextProps, nextState)
react性能优化非常重要的一环。组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,
如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧的dom树进行diff算法对比,
节省大量性能,尤其是在dom结构复杂的时候
返回一个布尔值。在组件接收到新的props或者state时被调用。
在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。
8、componentWillUpdata(nextProps, nextState)
组件初始化时不调用,只有在组件将要更新时才调用,此时可以修改state
9、render()
组件渲染
10、componentDidUpdate()
组件初始化时不调用,组件更新完成后调用,此时可以获取dom节点。
- 卸载
11、componentWillUnmount()
组件将要卸载时调用,一些事件监听和定时器需要在此时清除。
二、组件生命周期的执行次数是什么样子的
\](javascript:void(0)😉 只执行一次: constructor、componentWillMount、componentDidMount 执行多次:render 、子组件的componentWillReceiveProps、componentWillUpdate、componentDidUpdate 有条件的执行:componentWillUnmount(页面离开,组件销毁时) 不执行的:根组件(ReactDOM.render在DOM上的组件)的componentWillReceiveProps(因为压根没有父组件给传递props) \[\](javascript:void(0)😉 三、React生命周期执行顺序  **Mounting中为组件的挂载过程** componentWillMount组件挂载之前 render组件的渲染方法 componentDidMount组件挂载完成执行 **Updation中为组件数据发生变化的过程** props独有 componentWillReceiveProps 触发条件 1. 当一个组件从父组件接收了参数。 2.如果这个组件第一次被父组件加载的时候不会被执行。 3.这个组件之前已经存在于父组件中,并且接收的数据发生变动这时此方法才会被触发。 props和states共有 shouldComponentUpdata 是否要更新数据?需要一个返回值true继续执行下面的生命周期,false就会终止当前组件数 componentWillUpdate 组件将要更新 render组件的重新渲染 componentDidUpdata 组件完成更新 **Unmounting组件卸载** componentWillUnmount 组件销毁的时候触发 ### 14、**你了解 Virtual DOM 吗?解释一下它的工作原理。** Virtual DOM 是一个轻量级的 JavaScript 对象,它最初只是 real DOM 的副本。它是一个节点树,它将元素、它们的属性和内容作为对象及其属性。 React 的渲染函数从 React 组件中创建一个节点树。然后它响应数据模型中的变化来更新该树,该变化是由用户或系统完成的各种动作引起的。 Virtual DOM 工作过程有三个简单的步骤。 1. 每当底层数据发生改变时,整个 UI 都将在 Virtual DOM 描述中重新渲染。  2. 然后计算之前 DOM 表示与新表示的之间的差异。  3. 完成计算后,将只用实际更改的内容更新 real DOM。  ### 15、**为什么浏览器无法读取JSX?** 浏览器只能处理 JavaScript 对象,而不能读取常规 JavaScript 对象中的 JSX。所以为了使浏览器能够读取 JSX,首先,需要用像 Babel 这样的 JSX 转换器将 JSX 文件转换为 JavaScript 对象,然后再将其传给浏览器。 ### 16、**与 ES5 相比,React 的 ES6 语法有何不同?** 以下语法是 ES5 与 ES6 中的区别: 1. require 与 import ```react // ES5 var React = require('react'); // ES6 import React from 'react'; 12345 ``` 1. export 与 exports ```react // ES5 module.exports = Component; // ES6 export default Component; 12345 ``` 1. component 和 function ```react // ES5 var MyComponent = React.createClass({ render: function() { return
Hello Edureka!
; } }); // ES6 class MyComponent extends React.Component { render() { returnHello Edureka!
; } } 123456789101112131415 ``` 1. props ```react // ES5 var App = React.createClass({ propTypes: { name: React.PropTypes.string }, render: function() { returnHello, {this.props.name}!
; } }); // ES6 class App extends React.Component { render() { returnHello, {this.props.name}!
; } } 12345678910111213141516 ``` 1. state ```react // ES5 var App = React.createClass({ getInitialState: function() { return { name: 'world' }; }, render: function() { returnHello, {this.state.name}!
; } }); // ES6 class App extends React.Component { constructor() { super(); this.state = { name: 'world' }; } render() { returnHello, {this.state.name}!
; } } 12345678910111213141516171819202122 ``` **10. React与Angular有何不同?** | **主题** | **React** | **Angular** | |-----------|----------------|-------------| | *1. 体系结构* | 只有 MVC 中的 View | 完整的 MVC | | *2. 渲染* | 可以在服务器端渲染 | 客户端渲染 | | *3. DOM* | 使用 virtual DOM | 使用 real DOM | | *4. 数据绑定* | 单向数据绑定 | 双向数据绑定 | | *5. 调试* | 编译时调试 | 运行时调试 | | *6. 作者* | Facebook | Google | ### 17、**React与Angular有何不同?** | **主题** | **React** | **Angular** | |-----------|----------------|-------------| | *1. 体系结构* | 只有 MVC 中的 View | 完整的 MVC | | *2. 渲染* | 可以在服务器端渲染 | 客户端渲染 | | *3. DOM* | 使用 virtual DOM | 使用 real DOM | | *4. 数据绑定* | 单向数据绑定 | 双向数据绑定 | | *5. 调试* | 编译时调试 | 运行时调试 | | *6. 作者* | Facebook | Google | ### 18、**你理解"在React中,一切都是组件"这句话。** 组件是 React 应用 UI 的构建块。这些组件将整个 UI 分成小的独立并可重用的部分。每个组件彼此独立,而不会影响 UI 的其余部分。 ### 19、**解释 React 中 render() 的目的** 每个React组件强制要求必须有一个 **render()** 。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 `