React里里面试准备
Posted 鲸渔要加油
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React里里面试准备相关的知识,希望对你有一定的参考价值。
文章目录
- 项目描述
- 1、生命周期
- 2、Hook
- 3、hook包装函数优化
- 4、Redux
- 5、自己封装的组件
- 6、图片懒加载
- 7、说一下 connect 怎么使用
- 8、flex 布局
- 9、rem 布局
- 10、类组件 与 函数式组件 区别
- 11、Promise
- 12、Git
- 13、requesetAnimationFrame 有了解过吗
- 14、定位
- 16、数组和对象的方法
- 17、for in 和 Object.keys 的区别
- 18、宏任务和微任务
- 19、useState 为什么不能写在循环和判断里
- 20、单项绑定和双向绑定
- 21、闭包
- 22、http 状态码
- 23、如何解决跨域问题
- 24、理解JS中的错误(Error)
- 25、防抖、节流 怎么实现
- 26、antd form 表单 antd4
- 27、diff和dom
- 28、无线端和pc端css的区别
项目描述
这个项目是给古风设计师们进行资讯和活动,发布和管理的一个后台系统,我负责的模块是咨询管理,里面有咨询列表,添加咨询,子咨询列表,照片墙,有基本的咨询的增删改查功能,搜索功能,详情页查看功能,主要用的技术栈是 React
全家桶加 Ant Design
和第三方插件比如day.js,echarts,lodash之类,用的表单比较多,自己封装了公共组件和高阶组件,redux,还用了一些懒加载和优化技术
1、生命周期
根据父的props
componentWillReceiveProps()
是在 render
之前执行的函数,在函数的内部会接收 nextProps
参数,存储着本次更新的数据的值,this.props
存储上一次更新的数据的值,可以通过比较两数据值的不同来进行 setState
更新组件的状态,不会触发额外的 render
根据自己的数据更新
shouldComponentUpdate()
函数返回 true
时,才会触发render钩子
static getDerivedStateFromProps()
代替了 componentwillmount()
componentWillReceiveProps()
export default class TableActivity extends React.Component {
constructor(props) {
super(props);
this.state = { list: [] };
}
// props 是新值,state 是旧值
static getDerivedStateFromProps(props, state) {
if (props.list !== state.list) {
return { list: props.list };
}
return null;
}
render() {
return {};
}
}
getSnapshotBeforeUpdate()
的任何返回值都传给 **componentDidUpdate(preProps,preState,snapshot)
*的第三个参数,搭配使用
getSnapshotBeforeUpdate() {
// list 是新闻盒子
// scrollHeight 是盒子之前的高度
return this.refs.list.scrollHeight
}
componentDidUpdate(preProps,preState,height) {
// scrollTop 是盒子网上滚动的距离
// 盒子往上滚动的距离 += 当前盒子高 - 之前盒子高
this.refs.list.scrollTop += this.refs.list.scrollHeight - height
}
2、Hook
useState
定义state,修改state
useEffect
用于实现 componentDidMount
componentDidUpdate
componentWillUnmount
useContext
用于实现跨组件通信
useRef
用于绑定组件
useImperativehandle
搭配 useRef
获取子组件的方法
useLayoutEffect
功能和 useEffect
一致,但它在根组件使用
useDebugValue
浏览器中调试名称
useCallback
和 useMemo
是用来做优化的
函数组件是一个函数,数据一改,整个函数调用
用这两个让里面的函数不执行
达到不用每次重新声明新的函数,避免释放内存、分配内存的计算资源浪费
子组件不会因为这个函数的变动重新渲染。【和React.memo搭配使用】
useMemo
返回的是一个值要return一个值,监听另外一个值
export default function Aaa() {
const [num, setNum] = useState(0);
function list() {
console.log(123321123321);
return 1;
}
const total = useMemo(() => {
return list();
}, []);
return (
<div>
<button
onClick={() => {
setNum((num) => num + 1);
}}
>
{num}
</button>
<div>{total}</div>
</div>
);
}
useReducer
状态管理
export default function ReducerDemo() {
const [count, dispath] = useReducer((state,action)=> {
if(action === 'add'){
return state + 1;
}
return state;
}, 0);
return (
<div>
<h1>{count}</h1>
<button onClick={()=> dispath('add')}>Increment</button>
</div>
)
}
3、hook包装函数优化
父组件传的值没有改变,子组件就不重新渲染
子类组件用 React.PureComponent
export default class Child extends React.PureComponent {}
这样写
子函数组件用 function Child() {}
export default React.memo(Child)
如果父组件没有像子组件传参就写上面方法的就行
如果有传参和函数的时候就要用 useCallback
和 useMemo
函数直接写到 useCallback
里面,可以不用监听值
export default function Aaa() {
const [num, setNum] = useState(0);
const total = useCallback(() => {}, []);
return (
<div>
<button
onClick={() => {
setNum((num) => num + 1);
}}
>
{num}
</button>
<Bbb total={total} />
</div>
);
}
function Bbb() {
console.log(2342142142134);
return <div>123</div>;
}
export default React.memo(Bbb);
4、Redux
三大原则 单一数据源,State只读,只能action更新,纯函数修改
纯函数: 相同的输入必定得到相同输出,函数执行时没有副作用
Redux 基础
5、自己封装的组件
轮播组件
拖拽组件 addCommentDrop
draggable
onDragStart
onDragEnter
对话框
message提示
搜索组件
高阶组件 就是一个函数,这个函数接受一个组件作为输入,然后返回一个新的组件作为结果,而且,返回的新组件拥有函数封装的功能,复用
比如封装过返回页面就到之前看过的位置
1、先定义一个组件接受形参(组件),返回一个函数
import React, { Component } from 'react';
export function HocComp(Comp) {
return class _ extends Component {
game = () => {
const { type, cid } = this.props;
console.log(type, cid);
};
componentDidMount() {
document.documentElement.scrollTop = localStorage.getItem('scroll');
}
componentWillUnmount() {
localStorage.setItem('scroll', document.documentElement.scrollTop);
}
render() {
return <Comp game={this.game} />;
}
};
}
2、再定义一个组件
import React, { Component } from 'react';
export default class One extends Component {
render() {
const { game } = this.props;
return (
<div>
<button onClick={game}>One</button>
</div>
);
}
}
3、再在父级调用
import { HocComp } from './HOC/index';
import One from './components/One';
const WithOne = HocComp(One);
6、图片懒加载
获取屏幕可视区域的高度 document.documentElement.clientHeight
获取盒子到浏览器顶端的距离 aaa.getBoundingClientRect().top
或者 aaa.offsetTop
或者获取 body.scrollTop
滚动的距离
监听浏览器的滚动事件 window.onscroll
判断 盒子顶距离是否小于等于屏幕可视区高度
再用 getAttribute(data-src)
获取属性值替换 src
项目中用的是 IntersectionObserver
API 封装的
- 先
new
一个IntersectionObserver
- 再用
observe(box)
方法绑定一个dom
observer.observe(box)
- 解绑
observer.unobserve(box)
和停止监听observer.disconnect()
entries
的 intersectionRatio
属性为 0
,进入可视区 0<n<1
entries
的 isIntersecting
属性为 false
,进入可视区 true
let observer
observer = new IntersectionObserver((entries) => {
console.log(entries)
})
const box = document.querySelectorAll('.box')[0]
// 绑定
observer.observe(box)
// 解绑元素
observer.unobserve(box)
// 停止监听
observer.disconnect()
7、说一下 connect 怎么使用
React-Redux
将所有组件分为两大类:展示组件(UI组件),容器组件,connect
就是合并他们的,将 store
的数据作为 props
绑定到组件上
8、flex 布局
父级设置 display:flex
flex: 1 = flex-grow:1, flex-shrink:1, flex-basis:auto
flex-grow
设置子元素按比例占用父剩余宽度,默认 0
flex-shrink
超出父元素时按比缩小,默认 1
flex-basis
设置子元素宽度,如果超出父宽度就按比例均分,默认 auto
9、rem 布局
rem单位:rem (root em)是一个相对单位,是相对于html元素的字体大小
配合媒体查询
@media screen and (max-width: 800px) {
html {
font-size: 62.5% !important;
}
}
rem
是相对于根元素的 font-size
,em
是相对于父元素 font-size
10、类组件 与 函数式组件 区别
函数组件没有 this
,没有生命周期,没有状态 state
类组件中的 this
指向的是当前组件的实例对象,所有的生命周期钩子都来自于继承的 React.Component
中
函数组件是一个纯函数,它接收一个props对象返回一个react元素;而类组件需要去继承React.Component并且创建render函数返回react元素
执行了ReactDOM.render(<MyComponent/>
之后,发生了什么?
函数组件
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
类组件
1.React解析组件标签,找到MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实的DOM,随后呈现在页面中
函数式组件 setState
会合并吗?不会
11、Promise
Promise
Promise
是异步编程的一种解决方案,解决回调地狱
实例方法
.then()
得到异步任务正确的结果
.catch()
获取异常信息
.finally()
成功与否都会执行(不是正式标准)
静态方法(对象方法)
.all()
并发处理多个异步任务,所有任务都执行完了才能得到结果
.race()
并发处理多个异步任务,只要有一个任务执行完了就能得到结果
12、Git
Git
git cherry-pick 名称
合并单个 commit
git rebase —onto master 名称
合并连续多个 commit
git stash
能够将所有未提交的修改(工作区和暂存区)保存至堆栈中,用于后续恢复当前工作目录。
git add
git commit
git log
查看版本
git reset --hard
回退版本
git push
git clone
git pull
git branch
查看分支
git checkout
切换分支
13、requesetAnimationFrame 有了解过吗
requesetAnimationFrame
requestAnimationFrame是HTML5中提供的动画API,简称rAF,即请求动画帧。可以让浏览器优化并行的动画动作,更合理的重新排列动作序列,并把能够合并的动作放在一个渲染周期内完成,从而呈现出更流畅的动画效果。说rAF之前先来简单了解与之相关的几个概念。
优点:
运行在后台标签页或者隐藏的 iframe 里时,requestAnimationFrame() 暂停调用以提升性能和电池寿命
函数节流:在高频率事件(resize,scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,使用 requestAnimationFrame 可保证每个刷新间隔内,函数只被执行一次
14、定位
16、数组和对象的方法
17、for in 和 Object.keys 的区别
-
for-in
是js
中最常见的迭代语句,常常用来枚举对象的属性。某些情况下,可能按照随机顺序便利数组元素 -
Object
构造器有一个实例属性keys
,则可以返回以对象的属性为元素的数组。数组中属性名的顺序跟使用for-in
遍历返回的顺序是一样的 -
for-in
循环会枚举对象原型链上的可枚举属性,而Object.keys
不会
18、宏任务和微任务
宏任务包括:script(整体代码)
, setTimeout
, setInterval
, setImmediate
, I/O
, UI rendering
微任务包括:process.nextTick
, Promises
, Object.observe
, MutationObserver
19、useState 为什么不能写在循环和判断里
这是因为 React
通过单链表来管理 Hooks
update
阶段,每次调用 useState
,链表就会执行 next
向后移动一步。如果将 useState
写在条件判断中,假设条件判断不成立,没有执行里面的 useState
方法,会导致接下来所有的 useState
的取值出现偏移,从而导致异常发生
20、单项绑定和双向绑定
双向和单向只不过是框架封装程度上的差异,本质上两者是可以相互转换的
单向绑定的优点是相应的可以带来单向数据流,这样做的好处是所有状态变化都可以被记录、跟踪,状态变化通过手动调用通知,源头易追溯,没有“暗箱操作”。同时组件数据只有唯一的入口和出口,使得程序更直观更容易理解,有利于应用的可维护性。缺点则是代码量会相应的上升,数据的流转过程变长,从而出现很多类似的样板代码。同时由于对应用状态独立管理的严格要求(单一的全局store),在处理局部状态较多的场景时(如用户输入交互较多的“富表单型”应用),会显得啰嗦及繁琐。基本上双向绑定的优缺点就是单向绑定的镜像了。优点是在表单交互较多的场景下,会简化大量业务无关的代码。缺点就是由于都是“暗箱操作”,我们无法追踪局部状态的变化(虽然大部分情况下我们并不关心),潜在的行为太多也增加了出错时 debug 的难度。同时由于组件数据变化来源入口变得可能不止一个,新手玩家很容易将数据流转方向弄得紊乱,如果再缺乏一些“管制”手段,最后就很容易因为一处错误操作造成应用雪崩。这样来看,单向绑定跟双向绑定在功能上基本上是互补的,所以我们可以在合适的场景下使用合适的手段。比如在 UI控件 中(通常是类表单操作),我会使用双向的方式绑定数据;而其他场景则统一采用 单向 + inline event ( ) 的方式构建应用。
21、闭包
JS 闭包
①函数嵌套函数
②函数内部可以引用函数外部的参数和变量
③参数和变量不会被垃圾回收机制回收
22、http 状态码
状态码 | 原因短语 |
---|---|
100 | 消息响应 |
200 | 成功响应 |
301 | 永久移动 |
302 | 临时移动 |
400 | 请求语法错误 |
401 | 未授权,类似于403错误,不同点是401错误后,只要正确输入帐号密码,验证即可通过 |
403 | 没有权利访问 |
404 | 服务器找不到所请求的资源 |
408 | 请求超时 |
500 | 内部服务器错误 |
23、如何解决跨域问题
前端常见的跨域方案
JSONP 请求一段 JS 脚本,把执行这段脚本的结果当做数据】
的玩法。
所以,你能 POST 一段通过 script 标签引入的脚本吗?在这里根本没有设置请求格式的余地
24、理解JS中的错误(Error)
Error
Error构造函数 throw new Error('报错啦')
EvalError
表示错误的原因:与 eval() 有关
InternalError
创建一个代表javascript引擎内部错误的异常抛出的实例。 如: “递归太多”
RangeError
数值变量或参数超出其有效范围
ReferenceError
无效引用
SyntaxError
语法错误
TypeError
变量或参数不属于有效类型
URIError
给 encodeURI()或 decodeURl()传递的参数无效
25、防抖、节流 怎么实现
1. 防抖
防抖策略 是当事件被触发后,延迟 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时
输入框的防抖
var timer = null // 1. 防抖动的 timer
function debounceSearch(keywords) { // 2. 定义防抖的函数
timer = setTimeout(function() {
// 发起 JSONP 请求
getSuggestList(keywords)
}, 500)
}
$('#ipt').on('keyup', function() { // 3. 在触发 keyup 事件时,立即清空 timer
clearTimeout(timer)
// ...省略其他代码
debounceSearch(keywords)
})
2. 节流
节流策略,顾名思义,可以减少一段时间内事件的触发频率
鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次
预定义一个 timer 节流阀
当设置了鼠标跟随效果后,清空 timer 节流阀,方便下次开启延时器
执行事件的时候判断节流阀是否为空,如果不为空,则证明距离上次执行间隔不足16毫秒
26、antd form 表单 antd4
自定义校验注意事项
1 在自定义校验 callback
必须被调用
2 callback(‘xxx’)
表示校验未通过,callback()
表示校验通过
const validatorMax = (rule, value, callback) => {
callback('89');
};
<Form.Item
rules={[
{
validator: validatorMax,
},
]}
>
<Input />
</Form.Item>
27、diff和dom
28、无线端和pc端css的区别
以上是关于React里里面试准备的主要内容,如果未能解决你的问题,请参考以下文章