React 相关
1.fetch VS ajax VS axios传统 A
-
ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始 js 中,核心使用 XMLHttpRequest 对象,多个请求之间如果有先后关系的话,就会出现回调地狱。JQuery ajax 是对原生XHR 的封装
-
axios 是一个基于 Promise ,本质上也是对原生 XHR 的封装,只不过它是 Promise 的实现版本,符合最新的 ES 规范,
-
fetch 不是 ajax 的进一步封装,而是原生 js,没有使用 XMLHttpRequest对象。
2.React 事件处理---修改 this 指向
方式 1:通过 bind 方法进行原地绑定,从而改变 this 指向
方式 2:通过创建箭头函数
方式 3:在 constructor 中提前对事件进行绑定
方式 4:将事件调用的写法改为箭头函数的形式
3.请简述你对 react 的理解
React 起源于 facebook,react 是一个用于构建用户界面的 js 库
-
特点:声明式设计:react 采用范式声明,开发者只需要声明显示内容,react就会自动完成
-
高效: react 通过对 dom 的模拟(也就是虚拟 dom),最大限度的减少与 dom 的交互
-
灵活: react 可以和已知的库或者框架很好配合
-
组件: 通过 react 构建组件,让代码更容易复用,能够很好应用在大型项目开发中,把页面功能拆分成小模块 每个小模块就是组件
-
单向数据流: react 是单向数据流,数据通过 props 从父节点传递到子节点,如果父级的某个 props 改变了,react 会重新渲染所有的子节点
4.react 组件之间的数据传递
-
正向传值用 props
-
逆向传值用函数传值 通过事件调用函数传递
-
同级传值用 pubsub-js
-
用 pubsub.publish(事件名,数据)抛出数据
-
用 pubsub.subscribe(监听的事件,()=){})接收数据
-
跨组件传递 用 context 要使用 context 进行跨组件传值就需要使用createContext() 方 法, 这 个 方 法 有 两 个 对 象 provider 生 产者 Consumer 消费者
5.Vue 与 react 区别
相同点:
-
都支持服务器渲染
-
都有虚拟 dom,组件化开发,通过 props 参数进行父子组件数据的传递,
-
都实现 webcomponent 规范
-
都是数据驱动视图
-
都有状态管理,react 有 redux,vue 有 vuex
-
都有支持 native’的方案 react 有 react native vue 有 weex
不同点:
-
react 严格上只针对 mvc 的 view 层,vue 是 mvvm 模式
-
虚拟 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 对象中管理
6.请简述虚拟 dom 与 diff 算法
-
虚拟DOM也就是常说的虚拟节点,它是通过js的object对象模拟DOM中的节点,然后再通过特定的渲染方法将其渲染成真实的 DOM 节点。频繁的操作 DOM,或大量造成页面的重绘和回流
-
Diff 算法:把树形结构按照层级分解,只比较同级元素,给列表结构的每个单元添加唯一的 key 值,方便比较
7.你对组件的理解
可组合,可复用,可维护,可测试
8.调用 setState 之后发生了什么?
React 在调用 setState 后,react 会将传入的参数对象和组件当前的状态合并,触发调和过程,在调和过程中,react 会根据新的状态构建 react 元素树重新渲染整个UI 界面,在得到元素树之后,react 会自动计算新老节点的差异,根据差异对界面进行最小化重新渲染
9.react 生命周期函数
-
componentWillMount 组件渲染之前调用
-
componentDidMount 在第一次渲染之后调用
-
componentWillReceiveProps 在组件接收到一个新的 props 时调用
-
shouldComponentUpdate 判断组件是否更新 html
-
componentWillupdate 组件即将更新 html 时调用
-
componentDidupdate 在组件完成更新后立即调用
-
componentWillUnmount 在组件移除之前调用
10.为什么虚拟 dom 会提高性能?(必考)
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 虚拟dom diff 算法避免了没有必要的 dom 操作,从而提高性能
11.(组件的)状态(state)和属性(props)之间有何不同
Props 是一个从外部传进组件的参数,主要作用就是父组件向子组件传递数据,但是 props 对于使用它的组件来说是只读的,一旦赋值不能修改,只能通过外部组件主动传入新的 props 来重新渲染子组件。
一个组件的显示形态可以由数据状态和外部参数决定,外部参数是props,数据状态就是 state(约等于vue 的 data),首先,在组件初始化的时候,用 this.state 给组件设定一个初始的 state,在第一次渲染的时候就会用这个数据来渲染组件,state 不同于 props 一点是,state 可以修改,通过 this.setState()方法来修改 state
12.shouldComponentUpdate 是做什么的
这个 react 生命周期钩子函数是来解决这个问题:
在更新数据的时候用 setState 修改整个数据,数据变了之后,遍历的时候所有内容都要被重新渲染,数据量少还好,数据量大就会严重影响性能
解决办法:
- shouldcomponentupdate 在渲染前进行判断组件是否更新,更新了再渲染
- purecomponent(纯组件)省去了虚拟 dom 生成和对比的过程 在类组件中使用
- react.memo() 类似于纯组件 在无状态组件中使用
13.react diff 原理
它是基于三个策略:
-
tree diff web UI 中 dom 节点跨层级的移动操作特别少,可以忽略不计
-
component diff 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件会生成不同的树形结构
-
element diff 对于同一层级的一组子节点,他们可以通过唯一的 id 进行区分
14.何为受控组件
React 负责渲染表单的组件,值是来自于 state 控制的,输入表单元素称为受控组件
15.调用 super(props) 的目的是什么
Super()调用父类的构造方法,有 super,组件才有自己的 this,在组件全局中都可以使用 this,如果只是 constructor 而不执行 super,之后的 this 都是错的,super 继承父组件的 this
16.React 中构建组件的方式
-
自定义组件:函数组件或者无状态组件 组件首字母大写
-
类组件:一个类组件必须实现一个 render 方法,这个方法必须返回一个 jsx 元素,要用一个外层的元素把所有内容包裹起来
17.简 述 flux 思想
Flux 的最大特点,就是数据的"单向流动"。
- 用户访问 View
- View 发出用户的 Action
- Dispatcher 收到 Action,要求 Store 进行相应的更新
- Store 更新后,发出一个"change"事件
- View 收到"change"事件后,更新页面
18.React 项目用过什么脚手架?Mern? Yeoman?
Mern:MERN 是脚手架的工具,它可以很容易地使用 Mongo, Express, React and NodeJS 生成同构 JS 应用。它最大限度地减少安装时间,并得到您使用的成熟技术来加速开发。
19.应该在 React 组件的何处发起 Ajax 请求?
在 React 组件中,应该在 componentDidMount 中发起网络请求。这个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命周期中仅会执行一次。
更重要的是,你不能保证在组件挂载之前 Ajax 请求已经完成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。在componentDidMount 中发起网络请求将保证这有一个组件可以更新了。
20.何为高阶组件(higher order component)?
高阶组件是一个以组件为参数并返回一个新组件的函数。HOC
运行你重用代码、逻辑和引导抽象。最常见的可能是 Redux 的 connect 函数。除了简单分享工具库和简单的组合,HOC 最好的方式是共享 React 组件之间的行为。如果你发现你在不同的地方写了大量代码来做同一件事时,就应该考虑将代码重构为可重用的 HOC。
note
useState、useEffect
import { useState, useEffect } from "react";
useEffect:用于模仿生命周期,因为函数组件没有生命周期函数。具体模仿哪段生命周期,看传入的第二个参数。
useEffect(fn,other)的第二个参数是如何影响对应的 fiber树节点 创建 Passive effect 的呢?
对于类组件来说:
-
高阶组件:
本质是高阶函数,只不过是将参数变成了组件,返回值是新的组件。
-
路由:
window.location = 'xx' // 在当前tab,跳转 并 刷新浏览器
-
hash 路由:
- 通过 a 标签的锚点实现;
- 路由上有 #;
- window.location.hash = 'xx' // 在当前tab,不跳转 不刷新浏览器;
- 通过 window.addEventListener('hashchange', (e) => {}) 监听 hash 变化
-
history/browser 路由:
- 通过 history.pushState/replaceState 实现;
- history.pushState({name:'newPath', null, '/xx'}) // 在当前tab,不跳转 不刷新浏览器;
- 路由变化 监听
-
history.pushState = function() {
const historyEvent = history['pushState']; // 函数体
const newEvent = historyEvent.apply(this, arguments); // history.pushState() 函数调用,返回值是 undefined,可能是没有 return
const e = new Event(type);
e.arguments = arguments;
window.dispatchEvent(e);
return newEvent;
};
window.addEventListener('pushState', function(e) {
console.log('THEY DID IT AGAIN! pushState');
});