React综合指南(一)

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的主要功能如下:

  1. 它使用**虚拟DOM **而不是真正的DOM。
  2. 它可以用服务器端渲染
  3. 它遵循单向数据流或数据绑定。

4、类组件和函数组件的区别

定义组件有两个要求:

  1. 组件名称必须以大写字母开头
  2. 组件的返回值只能有一个根元素

函数组件

js 复制代码
function Welcome (props) {
  return <h1>Welcome {props.name}</h1>
}
ReactDOM.render(<Welcome name='react' />, document.getElementById('root'));
  1. 函数组件接收一个单一的 props 对象并返回了一个React元素

类组件

js 复制代码
class Welcome extends React.Component {
  render() {
    return (
      <h1>Welcome { this.props.name }</h1>
    );
  }
}
ReactDOM.render(<Welcome name='react' />, document.getElementById('root'));

  1. 无论是使用函数或是类来声明一个组件,它决不能修改它自己的 props
  2. 所有 React 组件都必须是纯函数,并禁止修改其自身 props
  3. React是单项数据流,父组件改变了属性,那么子组件视图会更新。
  4. 属性 props 是外界传递过来的,状态 state 是组件本身的,状态可以在组件中任意修改
  5. 组件的属性和状态改变都会更新视图。

区别

函数组件和类组件当然是有区别的,而且函数组件的性能比类组件的性能要高,因为类组件使用的时候要实例化,而函数组件直接执行函数取返回结果即可。为了提高性能,尽量使用函数组件。

区别 函数组件 类组件
是否有 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//

  • <NavLink activeClassName="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的一些主要优点是:

    1. 它提高了应用的性能
    2. 可以方便地在客户端和服务器端使用
    3. 由于 JSX,代码的可读性很好
    4. React 很容易与 Meteor,Angular 等其他框架集成
    5. 使用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的限制如下:

    1. React 只是一个库,而不是一个完整的框架
    2. 它的库非常庞大,需要时间来理解
    3. 新手程序员可能很难理解
    4. 编码变得复杂,因为它使用内联模板和 JSX

    10、什么是JSX?

    JSX 是J avaScript XML 的简写。是 React 使用的一种文件,它利用 JavaScript 的表现力和类似 HTML 的模板语法。这使得 HTML 文件非常容易理解。此文件能使应用非常可靠,并能够提高其性能。下面是JSX的一个例子:

    javascript 复制代码
    render(){
        return(        
            <div>
                <h1> Hello World from Edureka!!</h1>
            </div>
        );
    }

    11、react中不同组件之间如何做到数据交互?

    • 父组件向子组件通信:使用 props
    • 子组件向父组件通信:使用 props 回调
    • 跨级组件间通信:使用 context 对象
    • 非嵌套组件间通信:使用事件订阅

    事实上,在组件间进行通信时,这些通信方式都可以使用,区别只在于使用相应的通信方式的复杂程度和个人喜好,选择最合适的那一个。比如,通过事件订阅模式通信不止可以应用在非嵌套组件间,还可以用于跨级组件间,非嵌套组件间通信也可以使用 context 等。关键是选择最合适的方式。

    当然,自己实现组件间的通信还是太难以管理了,因此出现了很多状态管理工具,如 flux、redux 等,使用这些工具使得组件间的通信更容易追踪和管理。

    12、react中refs的作用是什么?

    • RefsReact 提供给我们的安全访问 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()

    组件将要卸载时调用,一些事件监听和定时器需要在此时清除。

    二、组件生命周期的执行次数是什么样子的

    ![复制代码](https://img-blog.csdnimg.cn/img_convert/5ee55cb53546b940153ac1b3bbcb822e.gif)\](javascript:void(0)😉 只执行一次: constructor、componentWillMount、componentDidMount 执行多次:render 、子组件的componentWillReceiveProps、componentWillUpdate、componentDidUpdate 有条件的执行:componentWillUnmount(页面离开,组件销毁时) 不执行的:根组件(ReactDOM.render在DOM上的组件)的componentWillReceiveProps(因为压根没有父组件给传递props) \[![复制代码](https://img-blog.csdnimg.cn/img_convert/2ea3533448fffa6496b8960cbd0106bf.gif)\](javascript:void(0)😉 三、React生命周期执行顺序 ![img](https://img-blog.csdnimg.cn/img_convert/b6f607f460a467570afcce823c925ec1.png) **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 描述中重新渲染。 ![Virtual DOM 1](https://img-blog.csdnimg.cn/20190325160134708.png) 2. 然后计算之前 DOM 表示与新表示的之间的差异。 ![Virtual DOM 2](https://img-blog.csdnimg.cn/20190325160145800.png) 3. 完成计算后,将只用实际更改的内容更新 real DOM。 ![Virtual DOM 3](https://img-blog.csdnimg.cn/20190325160158808.png) ### 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() { return

    Hello Edureka!

    ; } } 123456789101112131415 ``` 1. props ```react // ES5 var App = React.createClass({ propTypes: { name: React.PropTypes.string }, render: function() { return

    Hello, {this.props.name}!

    ; } }); // ES6 class App extends React.Component { render() { return

    Hello, {this.props.name}!

    ; } } 12345678910111213141516 ``` 1. state ```react // ES5 var App = React.createClass({ getInitialState: function() { return { name: 'world' }; }, render: function() { return

    Hello, {this.state.name}!

    ; } }); // ES6 class App extends React.Component { constructor() { super(); this.state = { name: 'world' }; } render() { return

    Hello, {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 元素,则必须将它们组合在一个封闭标记内,例如 `
    `、``、`
    ` 等。此函数必须保持纯净,即必须每次调用时都返回相同的结果。 ### 20、**如何将两个或多个组件嵌入到一个组件中?** 可以通过以下方式将组件嵌入到一个组件中: ```react class MyComponent extends React.Component{ render(){ return(

    Hello

    ); } } class Header extends React.Component{ render(){ return

    Header Component

    }; } ReactDOM.render( , document.getElementById('content') ); ```

相关推荐
小满zs17 分钟前
React-router v7 第四章(路由传参)
前端·react.js
小陈同学呦26 分钟前
聊聊双列瀑布流
前端·javascript·面试
来自星星的坤33 分钟前
SpringBoot 与 Vue3 实现前后端互联全解析
后端·ajax·前端框架·vue·springboot
键指江湖1 小时前
React 在组件间共享状态
前端·javascript·react.js
诸葛亮的芭蕉扇1 小时前
D3路网图技术文档
前端·javascript·vue.js·microsoft
小离a_a1 小时前
小程序css实现容器内 数据滚动 无缝衔接 点击暂停
前端·css·小程序
徐小夕2 小时前
花了2个月时间研究了市面上的4款开源表格组件,崩溃了,决定自己写一款
前端·javascript·react.js
by————组态2 小时前
低代码 Web 组态
前端·人工智能·物联网·低代码·数学建模·组态
拉不动的猪2 小时前
UniApp金融理财产品项目简单介绍
前端·javascript·面试
菜冬眠。2 小时前
uni-app/微信小程序接入腾讯位置服务地图选点插件
前端·微信小程序·uni-app