个人觉得如果是有技术基础支持的可以看看用作参考,初手不推荐看面试题(学习树顺序不对吸收不到太多营养)
我从个人经历和网上找了一些题以及一些被淡化的小知识供大家参考
1.什么是React,为什么用它
React:Facebook 推出的一款声明式的,高效的,灵活的用于创建用户界面的JavaScript 库
React是Facebook内部的一个JavaScript类库,于2013年开源,可用于创建web用户交互页面,引入了一种信访室来处理浏览器DOM
以前需要手动更新Dom费力记录状态——老旧且不具备扩展性有难以加入新功能。React用声明式定义各个时间点的用户界面,而且无需
关心数据变化时需要更新那一部分Dom,在任何时间点,React都能够以最小的Dom修改来更新整个应用程序。
2.什么是单页面,什么是多页面
单页面(SPA)/多页面(MPA)
单页面应用
缺点:
1.首屏时间慢,SEO差:单页应用的首屏时间慢,首屏时需要请求一次html,同时还要发送一次js请求,两次请求回来了,首屏才会展示
出来。相对于多页应用,首屏时间慢。
多页面应用
缺点:
1.页面切换慢:因为每次跳转都需要发出一个http请求,如果网络比较慢,在页面之间来回跳转时,就会发现明显的卡顿。
总结:
进行网页开发时,选择多页面
进行移动应用开发时,选择单页面
图片来源地址:https://juejin.cn/post/6844903512107663368
3.React和Vue分别是单页面还是多页面
官网上是单页面的安装方法,想要开发多页面
用webpack打包成多入口就可以变为多页面(简单说就是更改 webpack 的配置)
4.Axios,Fetch,Ajax的区别
Ajax:
$.ajax({
type: 'POST',
url: url,
data: data,
dataType: dataType,
success: function () {},
error: function () {}
});
Ajax是对原生XHR的封装,为了达到我们跨越的目的,增添了对JSONP的支持。经过这么多年的更新维护,不得不承认它已经很成熟,
能够满足我们的基本需求,但是随着react,vue新一代框架的兴起,以及ES规范的完善,更多API的更新,它逐渐暴露了自己的不足
针对MVC的编程设计,不符合现在前端MVVM的趋势
基于原生的XHR开发,XHR本身的架构不够清晰
JQuery较大,单纯使用ajax却要引入整个JQuery非常的不合理
虽然axios不支持jsonp,但是可以通过引入jsonp模块来解决
Axios:
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Vue2.0之后,自从尤雨溪推荐大家用axios替换JQuery ajax,Axios快速的得到大家的关注。Axios本质就是对原生XHR的封装,
增加了Promise的实,符合最新的ES规范,从它的官网上可以看到它有以下几条特性:
从 node.js 创建 http 请求
支持 Promise API
客户端支持防止CSRF(请求中携带cookie)
提供了一些并发请求的接口(重要,方便了很多的操作)
Axios既提供了并发的封装,体积也较小,也没有下文会提到的fetch的各种问题,当之无愧是现在最应该选用的请求的方式
Fetch:
fetch号称是AJAX的替代品,fetch是基于原生的XMLHttpRequest对象来实现数据请求的,同时也是基于Promise实现链式调用的。
符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里更好更方便的写法,诸如:
try {
let response = await fetch(url);
let data = await response.json();
console.log(data);
} catch(e) {
console.log("error:", e);
}
使用 await 后,告别面条式调用,将异步写成同步,身心舒畅。从上图可以看到await 后面可以跟 Promise 对象,表示等待
Promise resolve() 才会继续向下执行,如果 Promise 被 reject() 或抛出异常则会被外面的 try...catch 捕获。
坦白说,Jquery还是Axios都已经将xhr封装的足够好,使用起来也足够方便,但是Fetch还是得到很多开发者的认可,
说明它还是存在很多优势的:
更加底层,提供的API丰富(request, response)
脱离了XHR,是ES规范里新的实现方式
跨域处理(mode为"no-cors")
fetch('/testPost', {
method: 'post',
mode: 'no-cors',
data: {}
}).then(function() {});
但是在使用fetch的时候,也会遇到了一些问题:
fetch只对网络请求报错,对400,500都当做成功的请求,需要封装去处理
fetch默认不会带cookie,需要添加配置项fetch(url, {credentials: 'include'})
fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,
造成了流量的浪费
fetch没有办法原生监测请求的进度,而XHR可以
所有版本的 IE 均不支持原生 Fetch,fetch-ie8 会自动使用 XHR 做 polyfill。但在跨域时有个问题需要处理。IE8,
9 的 XHR 不支持 CORS 跨域,不支持传 Cookie!所以推荐使用 fetch-jsonp
来源地址:https://www.jianshu.com/p/6937c42e3db8
5.React生命周期
React16生命周期组件生命周期阶段
1、初始化
2、挂载
3、更新
4、卸载
ComponentWillMount:
在渲染前调用,在客户端也在服务端
ComponentDidMount:
第一次渲染后调用,只在客户端,之后组件已经生成了对应的Dom结构,可以通过this.getDomNode()来访问。如和其他JavaScript一起用,可在其中调用SetTimeout,SetInterval或发送Ajax请求等(防止阻塞Ui)
ComponentWillReceiveProps:
在组建接收到一个新的prop(更新后)被调用,这个方法在初始化Render时不会被调用
ShouldComponentUpdate:
返回一个布尔值,在接收props或state时被调用,初始或使用forceUpdate时不被调用(可以再你确认不需要更新组件时用)
ComponentWillUpdate:
在组建接收到新的props或state但没有render时被调用,初始时不被调用
ComponentDidUpdate:
在组件完成更新后立即调用,初始化时不会被调用
ComponentWillUnMount:
在组建从Dom中移除的时候立刻被调用
6.setState到底是异步还是同步?
先给出答案: 有时表现出异步,有时表现出同步注
合成事件:就是react 在组件中的onClick等都是属于它自定义的合成事件
原生事件:比如通过addeventListener添加的,dom中的原生事件
1:setState只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout 中都是同步的。
2:setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前
导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback)
中的callback拿到更新后的结果。
3:setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout中不会批量更新,在“异步”中如果对
同一个值进行多次setState,setState的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时setState多个不同的值,在更新时会
对其进行合并批量更新
7.Redux的流程
核心概念:Store:保存数据的地方,你可以把它看成一个容器,整个应用只能有一个Store。
State:Store对象包含所有数据,如果想得到某个时点的数据,就要对Store生成快照,这种时点的数据集合,就叫做State。
Action:State的变化,会导致View的变化。但是,用户接触不到State,只能接触到View。所以,State的变化必须是View导致的。Action就是
View发出的通知,表示State应该要发生变化了。
Action Creator:View要发送多少种消息,就会有多少种Action。如果都手写,会很麻烦,所以我们定义一个函数来生成Action
这个函数就叫Action Creator。
Reducer:Store收到Action以后,必须给出一个新的State,这样View才会发生变化。这种State的计算过程就叫做Reducer。
Reducer是一个函数,它接受Action和当前State作为参数,返回一个新的State。
dispatch:是View发出Action的唯一方法。
整个工作流程:
首先,用户(通过View)发出Action,发出方式就用到了dispatch方法。
然后,Store自动调用Reducer,并且传入两个参数:当前State和收到的Action,Reducer会返回新的State
State一旦有变化,Store就会调用监听函数,来更新View。
到这儿为止,一次用户交互流程结束。可以看到,在整个流程中数据都是单向流动的,这种方式保证了流程的清晰
8.了解React-hook么
Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。 如果你在编写函数组件并意识到需要向其添加一些 state,以前的做法是必须将其它转化为 class。现在你可以在现有的函数组件中使用 Hook。9.React常用的hooks么
useState
我们可以把这里的 state 看做我们在 class component 中使用的 this.state。 我们的每一次 setState 操作,在改变了值之后,都会引发 rerender 操作,从而触发页面的更新(但是如果没有改变的话,则不会触发 rerender,我们在后面将会利用这一特性做一件有趣的事情)。 同时,setState 可以以函数作为参数,这个时候我们可以获取到最新的 state 值(在第一个回调参数)。
import React, { useState } from 'react';
function App() {
const [ state, setState ] = useState(0);
return (
<span>{state}</span>
)
}
useEffect
可以说是所有 hooks API 中最像是声明周期的钩子了,很容易让人理解成为,如果依赖数组为空,那么它等价为 componentDidMount,但是真的这样吗?我们可以这样去理解我们的函数组件,函数组件的每次运行都相当于 class component 中的一次 render,每轮都会保留它的闭包,所以,我们的 useEffect 实际保留了它运行轮次的 state 和 props 状态(如果依赖不更新,那么状态不更新),这也就是 useEffect 和 componentDidMount 生命周期的关系。
import React, { useEffect } from 'react';
function App() {
useEffect(() => {
console.log('I am mount');
return () => {
console.log('before next run, I am cleaned');
}
}, []);
useLayoutEffect
useLayoutEffect 与 useEffect 的不同在于,useLayoutEffect 会在 DOM 渲染之前执行,而 useEffect 会在 DOM 渲染之后执行,所以我们可以利用这个特性,避免一些由于 DOM 渲染之后进行操作导致的白屏问题。
useCallback
useCallback 可以帮助我们缓存函数(useMemo同样可以做到,写法不同),通过手动控制依赖,做到减少因为函数的更新导致子组件的更新(带来的性能问题非常明显)
import React, { useCallback } from 'react';
function App() {
const cb = useCallback(() => { console.log('callback') }, []);
return (
<button onClick={cb}></button>
)
}
useMemo
useMemo 可以为我们的 function component 提供缓存的能力,在一些重计算的场景下,可以减少重复计算的次数,起到明显的性能提升。 当然,useMemo同样可以用来缓存组件,起到类似与 class component 中 shouldComponentUpdate 的作用,让我们手动通过管理依赖的方式做到控制子组件的更新(当然这个手动管理的成本是非常高的)
useRef
因为在 hooks 中,我们所声明的所有变量是只属于它的闭包的,所以,我们无法做到变量的一个共享。因为 immutable 的 state 并不适合我们存储一些不参与 UI 显示的变量。hooks 为我们提供了 useRef 去存储 mutable 的不参与 UI 显示的变量,并且可以在每一轮 render 中共享。
useRef 不仅可以用来存储对 Dom 元素的引用(它的本意),更可以用来存储我们需要在每轮 render 中共享的 mutable 的变量(可能非常常用)。
import React, { useRef } from 'react';
function App() {
const td = useRef(1);
console.log(td.current); // 1
...
useReducer
在当前版本中的 useReducer 事实上是对 useState 的一层封装,实现了 redux 的一套原理(之前的版本是 useState 是对 useReducer 的一层封装)
function useReducer(reducer, initialState) {
const [state, setState] = useState(initialState);
function dispatch(action) {
const nextState = reducer(state, action);
setState(nextState);
}
return [state, dispatch];
}
useContext
假定我们已经有了一个 Context ,并且我们的子组件已经在 Provider 包裹下,我们可以直接使用 useContext 去获取值,而非使用回调去获取值。 同时,我们也可以对某些 Context 进行 useContext 的封装,让我们可以在不同的组件中方便的使用 Context 中的数据。
// 假定我们已经有 Context
function Child(props) {
const { value } = useContext(Context);
return (
<div>
{value}
</div>
)
}
我们可以将 Context 、useReducer 与 useContext 结合起来,打造我们自己的 Redux
const CTX = React.createContext(null);
const reducer = (state, action) => {
switch(action.type) {
default:
reutrn state;
}
}
const Context = function({ children }) {
const [state, dispatch] = useReducer(reducer, {});
return (
<CTX.Provider value={ state, dispatch }>
{children}
</CTX.Provider>
)
}
10.虚拟DOM的优缺点
优点:保证性能下限: 虚拟DOM可以经过diff找出最小差异,然后批量进行patch,这种操作虽然比不上手动优化,但是比起粗暴的DOM操作性能要好很多,因此虚拟DOM可以保证性能下限 无需手动操作DOM: 虚拟DOM的diff和patch都是在一次更新中自动进行的,我们无需手动操作DOM,极大提高开发效率 跨平台: 虚拟DOM本质上是JavaScript对象,而DOM与平台强相关,相比之下虚拟DOM可以进行更方便地跨平台操作,例如服务器渲染、移动端开发等等
缺点:
无法进行极致优化: 在一些性能要求极高的应用中虚拟DOM无法进行针对性的极致优化,比如VScode采用直接手动操作DOM的方式进行极端的性能优化
11.什么是上下文Context
Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性。用法:在父组件上定义getChildContext方法,返回一个对象,然后它的子组件就可以通过this.context属性来获取
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
class Header extends Component{
render() {
return (
<div>
<Title/>
</div>
)
}
}
class Title extends Component{
static contextTypes={
color:PropTypes.string
}
render() {
return (
<div style={{color:this.context.color}}>
Title
</div>
)
}
}
class Main extends Component{
render() {
return (
<div>
<Content>
</Content>
</div>
)
}
}
class Content extends Component{
static contextTypes={
color: PropTypes.string,
changeColor:PropTypes.func
}
render() {
return (
<div style={{color:this.context.color}}>
Content
<button onClick={()=>this.context.changeColor('green')}>绿色</button>
<button onClick={()=>this.context.changeColor('orange')}>橙色</button>
</div>
)
}
}
class Page extends Component{
constructor() {
super();
this.state={color:'red'};
}
static childContextTypes={
color: PropTypes.string,
changeColor:PropTypes.func
}
getChildContext() {
return {
color: this.state.color,
changeColor:(color)=>{
this.setState({color})
}
}
}
render() {
return (
<div>
<Header/>
<Main/>
</div>
)
}
}
ReactDOM.render(<Page/>,document.querySelector('#root'));
原文地址:https://juejin.cn/post/6844903816857403405#heading-16(8)
12.React的数据流
React中的数据流动是单向的,自上而下流动,即由父组件传递给子组件。React中最重要的两个概念就是state和props。state顾名思义表示状态。它代表组件内部的状态,这些状态只在组件内部改变,它相当于函数的内部参数。而props相当于由函数外部传入的参数,它的数据传递过程就是在顶级组件初始化pros,然后自上而下便利整个组件树,重新渲染所有相关的子组件。
13.什么是state/props
state:
在 React 没有结合 Flux 或 Redux 框架前,它自身也同样可以管理组件的内部状态。在 React 中,把这类状态统一称为state。
props:
React的单向数据流,主要的流动管道就是 props。 需要注意的是props本身是不可变的。如果试图改变props的值时会报出类型错误的警告。组件的props一定来源于组件的默认属性或从父组件传递过来的属性。
14.PNG,GIF,JPG的区别
gif
8位像素,256色
无损压缩
支持简单动画
支持boolean透明
适合简单动画
png
有PNG8和truecolor PNG
PNG8类似GIF颜色上限为256,文件小,支持alpha透明度,无动画
适合图标、背景、按钮
jpeg
颜色限于256
有损压缩
可控制压缩质量
不支持透明
适合照片