react 高频知识点梳理
如何配置 React-Router 实现路由切换
(1)使用<Route>
组件
路由匹配是通过比较 <Route>
的 path 属性和当前地址的 pathname 来实现的。当一个 <Route>
匹配成功时,它将渲染其内容,当它不匹配时就会渲染 null。没有路径的 <Route>
将始终被匹配。
(2)结合使用 <Switch>
组件和 <Route>
组件
<Switch>
用于将 <Route>
分组。
<Switch>
不是分组 <Route>
所必须的,但他通常很有用。 一个 <Switch>
会遍历其所有的子 <Route>
元素,并仅渲染与当前地址匹配的第一个元素。
(3)使用 <Link>、 <NavLink>、<Redirect>
组件
<Link>
组件来在你的应用程序中创建链接。无论你在何处渲染一个<Link>
,都会在应用程序的 HTML 中渲染锚(<a>
)。
是一种特殊类型的 当它的 to 属性与当前地址匹配时,可以将其定义为"活跃的"。
当我们想强制导航时,可以渲染一个<Redirect>
,当一个<Redirect>
渲染时,它将使用它的 to 属性进行定向。
refs 的作用是什么,你在什么样的业务场景下使用 refs
操作 DOM,为什么操作 DOM?
场景
图片渲染好后,操作图片宽高。比如做个放大镜功能
React 组件命名推荐的方式是哪个?
通过引用而不是使用来命名组件 displayName。
使用 displayName 命名组件:
React 推荐的方法:
当渲染一个列表时,何为 key?设置 key 的目的是什么
Keys 会有助于 React 识别哪些 items
改变了,被添加了或者被移除了。Keys 应该被赋予数组内的元素以赋予(DOM)元素一个稳定的标识,选择一个 key 的最佳方法是使用一个字符串,该字符串能惟一地标识一个列表项。很多时候你会使用数据中的 IDs 作为 keys,当你没有稳定的 IDs 用于被渲染的 items
时,可以使用项目索引作为渲染项的 key,但这种方式并不推荐,如果 items
可以重新排序,就会导致 re-render
变慢。
Redux 和 Vuex 有什么区别,它们的共同思想
(1)Redux 和 Vuex 区别
Vuex 改进了 Redux 中的 Action 和 Reducer 函数,以 mutations 变化函数取代 Reducer,无需 switch,只需在对应的 mutation 函数里改变 state 值即可
Vuex 由于 Vue 自动重新渲染的特性,无需订阅重新渲染函数,只要生成新的 State 即可
Vuex 数据流的顺序是∶View 调用 store.commit 提交对应的请求到 Store 中对应的 mutation 函数->store 改变(vue 检测到数据变化自动渲染)
通俗点理解就是,vuex 弱化 dispatch,通过 commit 进行 store 状态的一次更变;取消了 action 概念,不必传入特定的 action 形式进行指定变更;弱化 reducer,基于 commit 参数直接对数据进行转变,使得框架更加简易;
(2)共同思想
单—的数据源
变化可以预测
本质上∶ redux 与 vuex 都是对 mvvm 思想的服务,将数据从视图中抽离的一种方案。
为什么调用 setState 而不是直接改变 state?
解答
如果您尝试直接改变组件的状态,React 将无法得知它需要重新渲染组件。通过使用setState()
方法,React 可以更新组件的 UI。
另外,您还可以谈谈如何不保证状态更新是同步的。如果需要基于另一个状态(或属性)更新组件的状态,请向setState()
传递一个函数,该函数将 state 和 props 作为其两个参数:
React-Router 的实现原理是什么?
客户端路由实现的思想:
基于 hash 的路由:通过监听
hashchange
事件,感知 hash 的变化改变 hash 可以直接通过 location.hash=xxx
基于 H5 history 路由:
改变 url 可以通过 history.pushState 和 resplaceState 等,会将 URL 压入堆栈,同时能够应用
history.go()
等 API监听 url 的变化可以通过自定义事件触发实现
react-router 实现的思想:
基于
history
库来实现上述不同的客户端路由实现思想,并且能够保存历史记录等,磨平浏览器差异,上层无感知通过维护的列表,在每次 URL 发生变化的回收,通过配置的 路由路径,匹配到对应的 Component,并且 render
React 声明组件有哪几种方法,有什么不同?
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 中像初始化组件属性一样声明的。
Redux 怎么实现属性传递,介绍下原理
react-redux 数据传输∶ view-->action-->reducer-->store-->view。看下点击事件的数据是如何通过 redux 传到 view 上:
view 上的 AddClick 事件通过 mapDispatchToProps 把数据传到 action ---> click:()=>dispatch(ADD)
action 的 ADD 传到 reducer 上
reducer 传到 store 上 const store = createStore(reducer);
store 再通过 mapStateToProps 映射穿到 view 上 text:State.text
代码示例∶
为什么使用 jsx 的组件中没有看到使用 react 却需要引入 react?
本质上来说 JSX 是React.createElement(component, props, ...children)
方法的语法糖。在 React 17 之前,如果使用了 JSX,其实就是在使用 React, babel
会把组件转换为 CreateElement
形式。在 React 17 之后,就不再需要引入,因为 babel
已经可以帮我们自动引入 react。
应该在 React 组件的何处发起 Ajax 请求
在 React 组件中,应该在 componentDidMount
中发起网络请求。这个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命周期中仅会执行一次。更重要的是,你不能保证在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在 componentDidMount
中发起网络请求将保证这有一个组件可以更新了。
react16 的错误边界(Error Boundaries)是什么
部分 UI 中的 JavaScript 错误不应该破坏整个应用程序。 为了解决 React 用户的这个问题,React 16 引入了一个 “错误边界(Error Boundaries)” 的新概念。
对 React-Fiber 的理解,它解决了什么问题?
React V15 在渲染时,会递归比对 VirtualDOM 树,找出需要变动的节点,然后同步更新它们, 一气呵成。这个过程期间, React 会占据浏览器资源,这会导致用户触发的事件得不到响应,并且会导致掉帧,导致用户感觉到卡顿。
为了给用户制造一种应用很快的“假象”,不能让一个任务长期霸占着资源。 可以将浏览器的渲染、布局、绘制、资源加载(例如 HTML 解析)、事件响应、脚本执行视作操作系统的“进程”,需要通过某些调度策略合理地分配 CPU 资源,从而提高浏览器的用户响应速率, 同时兼顾任务执行效率。
所以 React 通过 Fiber 架构,让这个执行过程变成可被中断。“适时”地让出 CPU 执行权,除了可以让浏览器及时地响应用户的交互,还有其他好处:
分批延时对 DOM 进行操作,避免一次性操作大量 DOM 节点,可以得到更好的用户体验;
给浏览器一点喘息的机会,它会对代码进行编译优化(JIT)及进行热代码优化,或者对 reflow 进行修正。
核心思想: Fiber 也称协程或者纤程。它和线程并不一样,协程本身是没有并发或者并行能力的(需要配合线程),它只是一种控制流程的让出机制。让出 CPU 的执行权,让 CPU 能在这段时间执行其他的操作。渲染的过程可以被中断,可以将控制权交回浏览器,让位给高优先级的任务,浏览器空闲后再恢复渲染。
React 的事件和普通的 HTML 事件有什么不同?
区别:
对于事件名称命名方式,原生事件为全小写,react 事件采用小驼峰;
对于事件函数处理语法,原生事件为字符串,react 事件为函数;
react 事件不能采用 return false 的方式来阻止浏览器的默认行为,而必须要地明确地调用
preventDefault()
来阻止默认行为。
合成事件是 react 模拟原生 DOM 事件所有能力的一个事件对象,其优点如下:
兼容所有浏览器,更好的跨平台;
将事件统一存放在一个数组,避免频繁的新增与删除(垃圾回收)。
方便 react 统一管理和事务机制。
事件的执行顺序为原生事件先执行,合成事件后执行,合成事件会冒泡绑定到 document 上,所以尽量避免原生事件与合成事件混用,如果原生事件阻止冒泡,可能会导致合成事件不执行,因为需要冒泡到 document 上合成事件才会执行。
Redux 原理及工作流程
(1)原理 Redux 源码主要分为以下几个模块文件
compose.js 提供从右到左进行函数式编程
createStore.js 提供作为生成唯一 store 的函数
combineReducers.js 提供合并多个 reducer 的函数,保证 store 的唯一性
bindActionCreators.js 可以让开发者在不直接接触 dispacth 的前提下进行更改 state 的操作
applyMiddleware.js 这个方法通过中间件来增强 dispatch 的功能
(2)工作流程
const store= createStore(fn)生成数据;
action: {type: Symble('action01), payload:'payload' }定义行为;
dispatch 发起 action:store.dispatch(doSomething('action001'));
reducer:处理 action,返回新的 state;
通俗点解释:
首先,用户(通过 View)发出 Action,发出方式就用到了 dispatch 方法
然后,Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action,Reducer 会返回新的 State
State—旦有变化,Store 就会调用监听函数,来更新 View
以 store 为核心,可以把它看成数据存储中心,但是他要更改数据的时候不能直接修改,数据修改更新的角色由 Reducers 来担任,store 只做存储,中间人,当 Reducers 的更新完成以后会通过 store 的订阅来通知 react component,组件把新的状态重新获取渲染,组件中也能主动发送 action,创建 action 后这个动作是不会执行的,所以要 dispatch 这个 action,让 store 通过 reducers 去做更新 React Component 就是 react 的每个组件。
React 高阶组件是什么,和普通组件有什么区别,适用什么场景
官方解释∶
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
高阶组件(HOC)就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件,它只是一种组件的设计模式,这种设计模式是由 react 自身的组合性质必然产生的。我们将它们称为纯组件,因为它们可以接受任何动态提供的子组件,但它们不会修改或复制其输入组件中的任何行为。
1)HOC 的优缺点
优点∶ 逻辑服用、不影响被包裹组件的内部逻辑。
缺点∶hoc 传递给被包裹组件的 props 容易和被包裹后的组件重名,进而被覆盖
2)适用场景
代码复用,逻辑抽象
渲染劫持
State 抽象和更改
Props 更改
3)具体应用例子
权限控制: 利用高阶组件的 条件渲染 特性可以对页面进行权限控制,权限控制一般分为两个维度:页面级别和 页面元素级别
组件渲染性能追踪: 借助父组件子组件生命周期规则捕获子组件的生命周期,可以方便的对某个组件的渲染时间进行记录∶
注意:withTiming 是利用 反向继承 实现的一个高阶组件,功能是计算被包裹组件(这里是 Home 组件)的渲染时间。
页面复用
React 组件的 state 和 props 有什么区别?
(1)props
props 是一个从外部传进组件的参数,主要作为就是从父组件向子组件传递数据,它具有可读性和不变性,只能通过外部组件主动传入新的 props 来重新渲染子组件,否则子组件的 props 以及展现形式不会改变。
(2)state
state 的主要作用是用于组件保存、控制以及修改自己的状态,它只能在 constructor 中初始化,它算是组件的私有属性,不可通过外部访问和修改,只能通过组件内部的 this.setState 来修改,修改 state 属性会导致组件的重新渲染。
(3)区别
props 是传递给组件的(类似于函数的形参),而 state 是在组件内被组件自己管理的(类似于在一个函数内声明的变量)。
props 是不可修改的,所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
state 是在组件中创建的,一般在 constructor 中初始化 state。state 是多变的、可以修改,每次 setState 都异步更新的。
用户不同权限 可以查看不同的页面 如何实现?
Js 方式
根据用户权限类型,把菜单配置成 json, 没有权限的直接不显示
react-router 方式 在 route 标签上 添加 onEnter 事件,进入路由之前替换到首页
自己封装一个 privateRouter 组件 里面判断是否有权限,有的话返回
没有权限的话 component 返回一个提示信息的组件。
扩展一下,如果是根据用权限来判断是否隐藏组件该怎么做呢?
react 可以使用高阶组件,在高阶组件里面判断是否有权限,然后判断是否返回组件,无权限返回 null
vue 可以使用自定义指令,如果没有权限移除组件
什么原因会促使你脱离 create-react-app 的依赖
当你想去配置 webpack 或 babel presets。
对 React Hook 的理解,它的实现原理是什么
React-Hooks 是 React 团队在 React 组件开发实践中,逐渐认知到的一个改进点,这背后其实涉及对类组件和函数组件两种组件形式的思考和侧重。
(1)类组件: 所谓类组件,就是基于 ES6 Class 这种写法,通过继承 React.Component 得来的 React 组件。以下是一个类组件:
可以看出,React 类组件内部预置了相当多的“现成的东西”等着我们去调度/定制,state 和生命周期就是这些“现成东西”中的典型。要想得到这些东西,难度也不大,只需要继承一个 React.Component 即可。
当然,这也是类组件的一个不便,它太繁杂了,对于解决许多问题来说,编写一个类组件实在是一个过于复杂的姿势。复杂的姿势必然带来高昂的理解成本,这也是我们所不想看到的。除此之外,由于开发者编写的逻辑在封装后是和组件粘在一起的,这就使得类组件内部的逻辑难以实现拆分和复用。
(2)函数组件:函数组件就是以函数的形态存在的 React 组件。早期并没有 React-Hooks,函数组件内部无法定义和维护 state,因此它还有一个别名叫“无状态组件”。以下是一个函数组件:
相比于类组件,函数组件肉眼可见的特质自然包括轻量、灵活、易于组织和维护、较低的学习成本等。
通过对比,从形态上可以对两种组件做区分,它们之间的区别如下:
类组件需要继承 class,函数组件不需要;
类组件可以访问生命周期方法,函数组件不能;
类组件中可以获取到实例化后的 this,并基于这个 this 做各种各样的事情,而函数组件不可以;
类组件中可以定义并维护 state(状态),而函数组件不可以;
除此之外,还有一些其他的不同。通过上面的区别,我们不能说谁好谁坏,它们各有自己的优势。在 React-Hooks 出现之前,类组件的能力边界明显强于函数组件。
实际上,类组件和函数组件之间,是面向对象和函数式编程这两套不同的设计思想之间的差异。而函数组件更加契合 React 框架的设计理念: React 组件本身的定位就是函数,一个输入数据、输出 UI 的函数。作为开发者,我们编写的是声明式的代码,而 React 框架的主要工作,就是及时地把声明式的代码转换为命令式的 DOM 操作,把数据层面的描述映射到用户可见的 UI 变化中去。这就意味着从原则上来讲,React 的数据应该总是紧紧地和渲染绑定在一起的,而类组件做不到这一点。函数组件就真正地将数据和渲染绑定到了一起。函数组件是一个更加匹配其设计理念、也更有利于逻辑拆分与重用的组件表达形式。
为了能让开发者更好的的去编写函数式组件。于是,React-Hooks 便应运而生。
React-Hooks 是一套能够使函数组件更强大、更灵活的“钩子”。
函数组件比起类组件少了很多东西,比如生命周期、对 state 的管理等。这就给函数组件的使用带来了非常多的局限性,导致我们并不能使用函数这种形式,写出一个真正的全功能的组件。而 React-Hooks 的出现,就是为了帮助函数组件补齐这些(相对于类组件来说)缺失的能力。
如果说函数组件是一台轻巧的快艇,那么 React-Hooks 就是一个内容丰富的零部件箱。“重装战舰”所预置的那些设备,这个箱子里基本全都有,同时它还不强制你全都要,而是允许你自由地选择和使用你需要的那些能力,然后将这些能力以 Hook(钩子)的形式“钩”进你的组件里,从而定制出一个最适合你的“专属战舰”。
评论