五,React
1.react 函数组件和 class 组件区别?
类组件视图是怎么更新的呢,首先第一次渲染的时候,会创建一个类的实例,之后在更新的时候,仅仅按照生命周期流程调用render,实例不会变; 而函数式组件每次渲染更新都会重新执行调用函数,hooks组件就是函数组件
函数组件的每一次渲染或者更新,都是把函数(重新)执行,产生一个全新的私有上下文
2.react useEffect 对应 class 组件的哪些生命周期?
react中用useEffect模拟组件生命周期_useeffect模拟生命周期_君君yui的博客-CSDN博客
// 模拟 class 组件的 componentDidMount 和 componentDidUpdate
// 第一个参数执行函数,第二个参数不传
useEffect(() => {
console.log('DidMount 和 DidUpdate')
})
// 模拟 class 组件的 componentDidMount
// 第一个参数执行函数,第二个参数传空数组[]
useEffect(() => {
console.log('加载完了componentDidMount')
}, []) // 第二个参数是 [] (不依赖于任何 state)
// 模拟 class 组件的 componentDidUpdate
// 第一个参数执行函数,第二个参数传state数组
useEffect(() => {
console.log('更新了')
}, [count, name]) // 第二个参数就是依赖的 state
// 模拟 class 组件的 componentDidMount 和 componentWillUnmount
useEffect(() => {
let timerId = window.setInterval(() => {
console.log(Date.now())
}, 1000)
// 返回一个函数
// 模拟 componentWillUnmount 组件销毁的时候 停止计时器
return () => {
window.clearInterval(timerId)
}
}, [])
扩展:----------------------------------------------------------------------------------------------------------
36.useEffect的基础知识和底层机制_哔哩哔哩_bilibili
useEffect和useLayoutEffect区别
图有误会,useEffect和useLayoutEfect执行候
更准确来,useEffect在浏览器获取dom,重绘之后执行,useLayoutEfect已经获取dom,没有重绘之前执行了
从react源码分析useEffect与useLayoutEffect的执行细节 - 掘金
3.谈谈React setState,例如React setState 怎么获取到更新后的值?异步函数中为什么 setState 会立即更新?
React中的setState如何实时的获取到更新之后的数据_react setstate 怎么获取到更新后的值_米 硕的博客-CSDN博客
(1).setState提供了一个回调函数供开发者使用,在回调函数中,我们可以实时的获取到更新之后的数据。
updateData = (newData) => {
this.setState(
{ data: newData },
() => {
//这里打印的是最新的state值
console.log(this.state.data);
}
);
}
(2).使用setTimeout定时器
(3).在原生事件中修改状态
扩展:-------------------------------------------------------------------------------------
setState()同步、异步总结
异步的情况:
- 由React控制的事件处理函数,以及生命周期函数调用setState时表现为异步 。
- 大部分开发中用到的都是React封装的事件,比如onChange、onClick、onTouchMove等(合成事件中),这些事件处理函数中的setState都是异步处理的。
同步的情况:
- React控制之外的事件中调用setState是同步更新的。
- 比如原生js绑定的事件,setTimeout/setInterval,ajax,promise.then内等 React 无法掌控的 APIs情况下,setState是同步更新state的
setState 是同步还是异步这个问题等 react18 普及以后就不会再有了,因为所有的 setState 都是异步批量执行了。
setState()的参数接收
setState()可以接收一个对象外,还可以接收一个函数。
区别:
传递对象
批处理,对相同变量进行的多次处理会合并为一个,并以最后一次的处理结果为准传递函数
链式调用,React 会把我们更新 state 的函数加入到一个队列里面,然后,按照函数的顺序依次调用。
同时,为每个函数传入 state 的前一个状态,这样,就能更合理的来更新我们的 state 了,该函数有两个参数:prevState
props
4.useState 为什么不能放到条件语句里面,谈谈使用的注意事项?
(使用 useState 需要注意的 5 个问题_usestate 初始化_夏安 的博客-CSDN博客)
下面是一个题目(避坑)
useState和setState比较
官方建议useState的使用方法
react18中无论放在哪里都是异步的,但是通过flushSync可以实现通过
react16中useState和setState一样,放在合成事件和生命周期中是异步的,放在其他异步中属于同步的
5.useRef
6.useMemo
7.useCallback
useTransition
useTransition使用
8.谈谈react的hooks
react hooks的本质是自变量与因变量,其中,usestate是自变量; useMemo以及useCallback是作为没有副作用的因变量; useEffect是作为有副作用的因变量; 为了方便操作更多的自变量,有了useReducer; 为了跨组件层级的操作自变量,有了useContent; 最后,为了让组件更加灵活,有了useRef
9.做过哪些 react 相关的优化?函数组件怎么实现 shouldComponentUpdate?
优化:
react的优化方法_react优化_Amy.Wang的博客-CSDN博客
1.render里面尽量减少新建变量和bind函数,传递参数是尽量减少传递参数的数量。
2.定制shouldComponentUpdate函数
3.使用React.PureComponent
4.使用React.memo来缓存组件
5.延迟加载不是立即需要的组件
React.loadable
React.Lazy/React.Suspense
6.调整CSS而不是强制组件加载和卸载
7.使用React.Fragment避免添加额外的DOM
在函数组件中,如何实现shouldComponentUpdate()_yxlazy的博客-CSDN博客
在函数组件中,我们该如何实现class组件才有的shouldComponentUpdate()生命周期呢?
首先我们必须知道shouldComponentUpdate()的作用是什么,官方文档解释的是,当props和state发生改变时,shouldComponentUpdate()会在渲染之前被调用,默认的返回值是true,当返回值为false时,将会阻止本次渲染
既然已经知道了它的作用,那我们在函数组件中该如何实现呢?
在函数组件中,要阻止组件重新渲染就需要使用到React.memo(),React.memo是类似于高阶组件,但只适用于函数组件,我们在第二个参数中,通过返回true来阻止函数组件的渲染。
10.如果有一个非常大的 react 页面,我想优先渲染某一部分,这该怎么做?
1.React.loadable, React-loadable支持React的服务端渲染
2.React.Lazy/React.Suspense , React.lazy和Suspense并不支持服务端渲染
// App.js
import './App.css';
import React from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import Loadable from 'react-loadable';
function MyLoadingComponent({ error }) {
if (error) {
return <div>Error!</div>;
} else {
return <div>Loading...</div>;
}
}
// react-loadable
const LoadableComponent = Loadable({
loader: () => import('./pages/home'),
loading: MyLoadingComponent,
});
// React.lazy/React.suspanse
const About = React.lazy(() => import('./pages/about'));
function MyComponent() {
return (
// 显示 <MyLoadingComponent> 组件直至 About 加载完成
<React.Suspense fallback={<MyLoadingComponent />}>
<div>
<About />
</div>
</React.Suspense>
);
}
class App extends React.Component {
render() {
return (
<BrowserRouter>
<Routes>
<Route path='/home' element={<LoadableComponent />} />
<Route path='/about' element={<MyComponent />} />
</Routes>
<div>
<Link to='/home'>Home</Link>
<br />
<Link to='/about'>About</Link>
</div>
</BrowserRouter>
);
}
}
11.使用 Redux 的好处,以及和 Mobx 的区别
React -- redux详解_Sco_Jing1031的博客-CSDN博客_react redux
Redux:
redux的核心
redux有三个核心概念:
1、action:是动作的对象,包含2个属性
type:标识属性, 值为字符串, 唯一, 必要属性
data:数据属性, 值类型任意, 可选属性
例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }
2、reducer:用于初始化状态、加工状态。
加工时,根据旧的state和action, 产生新的state的纯函数。
3、store:将state、action、reducer联系在一起的对象,它内部维护着:state、reducer
得到此对象的方法:
import {createStore} from 'redux'
import reducer from './reducers'
const store = createStore(reducer)
此对象的功能:
getState(): 得到state
dispatch(action): 分发action, 触发reducer调用, 产生新的state
subscribe(listener): 注册监听,订阅,当产生了新的state时, 自动调用
mobx:
运行机制:
上面这个模型图描述了单向数据流思想,主要是状态state的改变,会对应页面UI的改变,页面UI上用户事件的操作会触发Actions的操作再去更新状态。
在Mobx里,它的状态state叫做observables-可观察的状态值,它的UI和副作用(reactions)就是observers-观察者,当observables发生改变时会通知到它的observers,然后观察者可以通过actions做一下处理,再通知observables更新。
要点:
1、定义状态使其可观察
2、创建视图响应状态变化
3、更改状态
核心概念:
1.observable:可观察的状态值
2.actions:一些改变状态值的动作
3.computed:根据state的改变,计算出来的值
4.reactions:因state或者computed value变化而引起的反应,主要指的是UI重新渲染
常用的装饰器:
@observable:将一个变量变得可观察
@observer常用于React组件,可监视render函数里使用的可观察变量,从而做出相应的reactions
@autorun常用于组件类或者store类里面,监视函数参数里使用的可观察变量,一旦变量发生变化。做出相对于的reactions
@action 改变观察变量值的操作
@computed 通过可观察变量经过函数计算得来的值,使用的时候才会计算,没有用到的时候不会计算。
Mbox与Redux对比:
首先它们都是状态管理库,无论是Redux还是Mobx,本质都是为了解决状态管理混乱,无法有效同步的问题,它们都支持:
1.统一维护管理应用状态;
2.操作更新状态方式统一,并且可控(通常以action方式提供更新状态的途径);
3.支持将store与React组件连接,如react-redux,mobx-react;通常使用状态管理库后,我们将React组件从业务上划分为两类:
容器组件(Container Components):负责处理具体业务和状态数据,将业务或状态处理函数传入展示型组件;
展示型组件(Presentation Components):负责展示视图,视图交互回调内调用传入的处理函数;
区别:
1.函数式和面向对象
Redux更多的是遵循函数式编程思想,而Mobx则更多从面相对象角度考虑问题。
Redux提倡编写函数式代码,如reducer就是一个纯函数,纯函数,接受输入,然后输出结果,除此之外不会有任何影响,也包括不会影响接收的参数;对于相同的输入总是输出相同的结果。
Mobx设计更多偏向于面向对象编程和响应式编程,通常将状态包装成可观察对象,于是我们就可以使用可观察对象的所有能力,一旦状态对象变更,就能自动获得更新。
2.单一store和多store
store是应用管理数据的地方,在Redux应用中,我们总是将所有共享的应用数据集中在一个大的store中,而Mobx则通常按模块将应用状态划分,在多个独立的store中管理。
3.JavaScript对象和可观察对象
Redux默认以JavaScript原生对象形式存储数据,而Mobx使用可观察对象:
Redux需要手动追踪所有状态对象的变更;
Mobx中可以监听可观察对象,当其变更时将自动触发监听;
4.不可变和可变
Redux状态对象通常是不可变的,我们不能直接操作状态对象,而总是在原来状态对象基础上返回一个新的状态对象。
而Mobx中可以直接使用新值更新状态对象。
5.mobx-react和react-redux
使用Redux和React应用连接时,需要使用react-redux提供的Provider和connect:
Provider:负责将Store注入React应用;
connect:负责将store state注入容器组件,并选择特定状态作为容器组件props传递;
对于Mobx而言,同样需要两个步骤:
Provider:使用mobx-react提供的Provider将所有stores注入应用;
使用inject将特定store注入某组件,store可以传递状态或action;然后使用observer保证组件能响应store中的可观察对象(observable)变更,即store更新,组件视图响应式更新。
12.React hook 为什么不能再条件和循环中使用
https://juejin.cn/post/6844903704437456909
为什么react的hook不能在条件语句和循环语句中用,可vue3源于Hook理念的组合式Api可以? - 知乎
在我们执行functionalComponent
的时候,在第一次执行到useState
的时候,他会对应Fiber
对象上的memoizedState
,这个属性原来设计来是用来存储ClassComponent
的state
的,因为在ClassComponent
中state
是一整个对象,所以可以和memoizedState
一一对应。
但是在Hooks
中,React并不知道我们调用了几次useState
,所以在保存state
这件事情上,React想出了一个比较有意思的方案,那就是调用useState
后设置在memoizedState
上的对象长这样:
{
baseState,
next,
baseUpdate,
queue,
memoizedState
}
我们叫他Hook对象。这里面我们最需要关心的是memoizedState
和next
,memoizedState
是用来记录这个useState
应该返回的结果的,而next
指向的是下一次useState
对应的`Hook对象。
每个在FunctionalComponent
中调用的useState
都会有一个对应的Hook
对象,他们按照执行的顺序以类似链表的数据格式存放在Fiber.memoizedState
上
重点来了:就是因为是以这种方式进行state
的存储,所以useState
(包括其他的Hooks)都必须在FunctionalComponent
的根作用域中声明,也就是不能在if
或者循环中声明
最主要的原因就是你不能确保这些条件语句每次执行的次数是一样的,也就是说如果第一次我们创建了state1 => hook1, state2 => hook2, state3 => hook3
这样的对应关系之后,下一次执行因为something
条件没达成,导致useState(1)
没有执行,那么运行useState(2)
的时候,拿到的hook
对象是state1
的,那么整个逻辑就乱套了,所以这个条件是必须要遵守的!
13.react 和 react-dom 的区别是什么?
react和reactdom有什么区别-前端问答-PHP中文网
react和reactdom的区别是:ReactDom只做和浏览器或DOM相关的操作,例如“ReactDOM.findDOMNode()”操作;而react负责除浏览器和DOM以外的相关操作,ReactDom是React的一部分。
React 在v0.14之前是没有 ReactDOM 的,所有功能都包含在 React 里。从v0.14(2015-10)开始,React 才被拆分成React 和 ReactDOM。为什么要把 React 和 ReactDOM 分开呢?因为有了 ReactNative。React 只包含了 Web 和 Mobile 通用的核心部分,负责 Dom 操作的分到 ReactDOM 中,负责 Mobile 的包含在 ReactNative 中
14.react diff 的复杂度,以及 react diff 的原理
React diff 算法的底层原理_前端之神的博客-CSDN博客_react diff算法原理
传统diff算法通过循环递归对节点进行依次对比,效率低下,算法复杂度达到 O(n^3),react
将算法进行一个优化,复杂度姜降O(n)
React中的diff算法
策略一:tree diff —— 层级对比
由于开发过程中极少出现DOM的跨层级移动,所以tree diff 忽略了DOM节点的跨层级移动。(react不建议开发人员跨层级移动DOM)
策略二:component diff —— 组件对比
同类型的两个组件,直接比较Virtual DOM树,不同类型的组件将会被判定作为脏组件(dirty component)处理,直接删除或创建新组件
策略三:element diff —— 节点对比
对于同一层级的一组子节点,通过分配唯一唯一key值进行区分
vue 和 react 在虚拟dom的diff上,做了哪些改进使得速度很快?
https://www.cnblogs.com/zpy521hl/p/16966097.html
15.
useState 怎么做缓存的?
16.怎么解决 useState 闭包的问题?
17.useReducer 比 redux 好在哪里?
18.react生命周期
挂载:在组件实例被创建并插入到dom中时,生命周期调用顺序如下
constructor
componentWillMount
getDerivedStateFromProps
render
componentDidMount
更新:当组件的 props 或 state 发生变化时会触发更新。
componentWillReceiveProps ()
shouldComponentUpdate
componentWillUpdate
getSnapshotBeforeUpdate
componentDidUpdate
卸载:当组件从 DOM中移除时会调用如下方法:
componentWillUnmount()
react源码读过吗,读过那些?
懒加载如何判断元素出现在视口内?(https://juejin.cn/post/719445360710883)
React专项面试题(高频
)
六. 其他
1.跨域,以及如何解决?
2.如何判断是手机端还是PC端,移动端适配怎么做?
如何判断是pc端还是移动端_如何判断是手机端还是pc端_前端江太公的博客-CSDN博客
判断网页打开的是移动端还是PC端_如何判断是手机端还是pc端_。 7.的博客-CSDN博客
1.navigator.userAgent
2.通过屏幕宽度判断是否为手机。直接获取window.screen
移动端适配详解 , 给你解决适配烦恼_玄鱼殇的博客-CSDN博客
1.百分比
2.rem+动态改变font-size
3.vw
4.flex
3.浏览器如何做静态资源缓存
浏览器缓存_浏览器如何做静态资源缓存_前端WebCode的博客-CSDN博客
强缓存和协商缓存
4.如何实现全网置灰
https://blog.csdn.net/aaqingying/article/details/12849625
css3新属性 filter:greyScale(1)