React里里面试准备

项目描述

这个项目是给古风设计师们进行资讯和活动,发布和管理的一个后台系统,我负责的模块是咨询管理,里面有咨询列表,添加咨询,子咨询列表,照片墙,有基本的咨询的增删改查功能,搜索功能,详情页查看功能,主要用的技术栈是 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

它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性

useState 定义state,修改state

useEffect 用于实现 componentDidMount componentDidUpdate componentWillUnmount

useContext 用于实现跨组件通信

useRef 用于绑定组件

useImperativehandle 搭配 useRef 获取子组件的方法

useLayoutEffect 功能和 useEffect 一致,但它在根组件使用

useDebugValue 浏览器中调试名称

useCallbackuseMemo 是用来做优化的
函数组件是一个函数,数据一改,整个函数调用
用这两个让里面的函数不执行
达到不用每次重新声明新的函数,避免释放内存、分配内存的计算资源浪费
子组件不会因为这个函数的变动重新渲染。【和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)

如果父组件没有像子组件传参就写上面方法的就行
如果有传参函数的时候就要用 useCallbackuseMemo
函数直接写到 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、自己封装的组件

自定义 Hook
轮询请求数据的时候封装过
监视屏幕高度让返回页面再上一次的位置

有一段代码再不同情况里出现,就把它封装成一个函数在各个地方调用,为了复用

轮播组件
拖拽组件 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()

entriesintersectionRatio 属性为 0,进入可视区 0<n<1
entriesisIntersecting 属性为 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

flex 布局基础



9、rem 布局

rem单位:rem (root em)是一个相对单位,是相对于html元素的字体大小

配合媒体查询

@media screen and (max-width: 800px) {
	html {
		font-size: 62.5% !important;
	}
}

rem 是相对于根元素的 font-sizeem 是相对于父元素 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
requestAnimationFrameHTML5中提供的动画API,简称rAF,即请求动画帧。可以让浏览器优化并行的动画动作,更合理的重新排列动作序列,并把能够合并的动作放在一个渲染周期内完成,从而呈现出更流畅的动画效果。说rAF之前先来简单了解与之相关的几个概念。
优点:
运行在后台标签页或者隐藏的 iframe 里时,requestAnimationFrame() 暂停调用以提升性能和电池寿命
函数节流:在高频率事件(resize,scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,使用 requestAnimationFrame 可保证每个刷新间隔内,函数只被执行一次



14、定位

定位



16、数组和对象的方法

数组和对象的方法



17、for in 和 Object.keys 的区别

  • for-injs 中最常见的迭代语句,常常用来枚举对象的属性。某些情况下,可能按照随机顺序便利数组元素

  • 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)

理解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

dom
diff 简单
diff 复杂



28、无线端和pc端css的区别

无线端和pc端css的区别

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值