前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >社招前端常见react面试题(必备)_2023-02-26

社招前端常见react面试题(必备)_2023-02-26

原创
作者头像
用户10358021
发布2023-02-26 16:54:20
1.5K0
发布2023-02-26 16:54:20
举报
文章被收录于专栏:前端面试2前端面试2

解释 React 中 render() 的目的。

每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 <form><group><div> 等。此函数必须保持纯净,即必须每次调用时都返回相同的结果。

React中constructor和getInitialState的区别?

两者都是用来初始化state的。前者是ES6中的语法,后者是ES5中的语法,新版本的React中已经废弃了该方法。

getInitialState是ES5中的方法,如果使用createClass方法创建一个Component组件,可以自动调用它的getInitialState方法来获取初始化的State对象,

代码语言:javascript
复制
var APP = React.creatClass ({
  getInitialState() {
    return { 
        userName: 'hi',
        userId: 0
     };
 }
})

React在ES6的实现中去掉了getInitialState这个hook函数,规定state在constructor中实现,如下:

代码语言:javascript
复制
Class App extends React.Component{
    constructor(props){
      super(props);
      this.state={};
    }
  }

对React-Fiber的理解,它解决了什么问题?

React V15 在渲染时,会递归比对 VirtualDOM 树,找出需要变动的节点,然后同步更新它们, 一气呵成。这个过程期间, React 会占据浏览器资源,这会导致用户触发的事件得不到响应,并且会导致掉帧,导致用户感觉到卡顿

为了给用户制造一种应用很快的“假象”,不能让一个任务长期霸占着资源。 可以将浏览器的渲染、布局、绘制、资源加载(例如 HTML 解析)、事件响应、脚本执行视作操作系统的“进程”,需要通过某些调度策略合理地分配 CPU 资源,从而提高浏览器的用户响应速率, 同时兼顾任务执行效率。

所以 React 通过Fiber 架构,让这个执行过程变成可被中断。“适时”地让出 CPU 执行权,除了可以让浏览器及时地响应用户的交互,还有其他好处:

  • 分批延时对DOM进行操作,避免一次性操作大量 DOM 节点,可以得到更好的用户体验;
  • 给浏览器一点喘息的机会,它会对代码进行编译优化(JIT)及进行热代码优化,或者对 reflow 进行修正。

核心思想: Fiber 也称协程或者纤程。它和线程并不一样,协程本身是没有并发或者并行能力的(需要配合线程),它只是一种控制流程的让出机制。让出 CPU 的执行权,让 CPU 能在这段时间执行其他的操作。渲染的过程可以被中断,可以将控制权交回浏览器,让位给高优先级的任务,浏览器空闲后再恢复渲染。

在 React 中,何为 state

State 和 props 类似,但它是私有的,并且完全由组件自身控制。State 本质上是一个持有数据,并决定组件如何渲染的对象。

React.Component 和 React.PureComponent 的区别

PureComponent表示一个纯组件,可以用来优化React程序,减少render函数执行的次数,从而提高组件的性能。

在React中,当prop或者state发生变化时,可以通过在shouldComponentUpdate生命周期函数中执行return false来阻止页面的更新,从而减少不必要的render执行。React.PureComponent会自动执行 shouldComponentUpdate。

不过,pureComponent中的 shouldComponentUpdate() 进行的是浅比较,也就是说如果是引用数据类型的数据,只会比较不是同一个地址,而不会比较这个地址里面的数据是否一致。浅比较会忽略属性和或状态突变情况,其实也就是数据引用指针没有变化,而数据发生改变的时候render是不会执行的。如果需要重新渲染那么就需要重新开辟空间引用数据。PureComponent一般会用在一些纯展示组件上。

使用pureComponent的好处:当组件更新时,如果组件的props或者state都没有改变,render函数就不会触发。省去虚拟DOM的生成和对比过程,达到提升性能的目的。这是因为react自动做了一层浅比较。

除了在构造函数中绑定 this,还有其它方式吗

你可以使用属性初始值设定项(property initializers)来正确绑定回调,create-react-app 也是默认支持的。在回调中你可以使用箭头函数,但问题是每次组件渲染时都会创建一个新的回调。

调用 setState 之后发生了什么

在代码中调用 setState 函数之后,React 会将传入的参数与之前的状态进行合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在 React 得到元素树之后,React 会计算出新的树和老的树之间的差异,然后根据差异对界面进行最小化重新渲染。通过 diff 算法,React 能够精确制导哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

  • 在 setState 的时候,React 会为当前节点创建一个 updateQueue 的更新列队。
  • 然后会触发 reconciliation 过程,在这个过程中,会使用名为 Fiber 的调度算法,开始生成新的 Fiber 树, Fiber 算法的最大特点是可以做到异步可中断的执行。
  • 然后 React Scheduler 会根据优先级高低,先执行优先级高的节点,具体是执行 doWork 方法。
  • 在 doWork 方法中,React 会执行一遍 updateQueue 中的方法,以获得新的节点。然后对比新旧节点,为老节点打上 更新、插入、替换 等 Tag。
  • 当前节点 doWork 完成后,会执行 performUnitOfWork 方法获得新节点,然后再重复上面的过程。
  • 当所有节点都 doWork 完成后,会触发 commitRoot 方法,React 进入 commit 阶段。
  • 在 commit 阶段中,React 会根据前面为各个节点打的 Tag,一次性更新整个 dom 元素

react-redux 的实现原理?

通过 redux 和 react context 配合使用,并借助高阶函数,实现了 react-redux

react中的Portal是什么?

Portals 提供了一种很好的将子节点渲染到父组件以外的 DOM 节点的方式。

第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或碎片。

第二个参数(container)则是一个 DOM 元素。

代码语言:javascript
复制
ReactDOM.createPortal(child, container)

说说 React组件开发中关于作用域的常见问题。

在 EMAScript5语法规范中,关于作用域的常见问题如下。

(1)在map等方法的回调函数中,要绑定作用域this(通过bind方法)。

(2)父组件传递给子组件方法的作用域是父组件实例化对象,无法改变。

(3)组件事件回调函数方法的作用域是组件实例化对象(绑定父组件提供的方法就是父组件实例化对象),无法改变。

在 EMAScript6语法规范中,关于作用域的常见问题如下。

(1)当使用箭头函数作为map等方法的回调函数时,箭头函数的作用域是当前组件的实例化对象(即箭头函数的作用域是定义时的作用域),无须绑定作用域。

(2)事件回调函数要绑定组件作用域。

(3)父组件传递方法要绑定父组件作用域。

总之,在 EMAScript6语法规范中,组件方法的作用域是可以改变的。

Component, Element, Instance 之间有什么区别和联系?

  • 元素: 一个元素element是一个普通对象(plain object),描述了对于一个DOM节点或者其他组件component,你想让它在屏幕上呈现成什么样子。元素element可以在它的属性props中包含其他元素(译注:用于形成元素树)。创建一个React元素element成本很低。元素element创建之后是不可变的。
  • 组件: 一个组件component可以通过多种方式声明。可以是带有一个render()方法的类,简单点也可以定义为一个函数。这两种情况下,它都把属性props作为输入,把返回的一棵元素树作为输出。
  • 实例: 一个实例instance是你在所写的组件类component class中使用关键字this所指向的东西(译注:组件实例)。它用来存储本地状态和响应生命周期事件很有用。

函数式组件(Functional component)根本没有实例instance。类组件(Class component)有实例instance,但是永远也不需要直接创建一个组件的实例,因为React帮我们做了这些。

为什么要使用 React. Children. map( props. children,( )=>)而不是props. children. map ( ( ) => )?

因为不能保证 props. children将是一个数组。

以下面的代码为例。

代码语言:javascript
复制
<Parent>
    <h1>有课前端网</h1>
</Parent>

在父组件内部,如果尝试使用 props.children. map映射子对象,则会抛出错误,因为props. children是一个对象,而不是一个数组。

如果有多个子元素, React会使 props.children成为一个数组,如下所示。

代码语言:javascript
复制
<Parent>
  <h1>有课前端网</h1>
  <h2>前端技术学习平台</h2>
</Parent>;
//不建议使用如下方式,在这个案例中会抛出错误。

class Parent extends Component {
  render() {
    return <div> {this.props.children.map((obj) => obj)}</div>;
  }
}

建议使用如下方式,避免在上一个案例中抛出错误。

代码语言:javascript
复制
class Parent extends Component {
  render() {
    return <div> {React.Children.map(this.props.children, (obj) => obj)}</div>;
  }
}

何为 Children

在JSX表达式中,一个开始标签(比如<a>)和一个关闭标签(比如</a>)之间的内容会作为一个特殊的属性props.children被自动传递给包含着它的组件。

这个属性有许多可用的方法,包括 React.Children.mapReact.Children.forEachReact.Children.countReact.Children.onlyReact.Children.toArray

简述react事件机制

当用户在为onClick添加函数时,React并没有将Click时间绑定在DOM上面

而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装交给中间层SyntheticEvent(负责所有事件合成)

所以当事件触发的时候,对使用统一的分发函数dispatchEvent将指定函数执行。React在自己的合成事件中重写了 stopPropagation方法,将 isPropagationStopped设置为 true,然后在遍历每一级事件的过程中根据此遍历判断是否继续执行。这就是 React自己实现的冒泡机制

React实现的移动应用中,如果出现卡顿,有哪些可以考虑的优化方案

  • 增加shouldComponentUpdate钩子对新旧props进行比较,如果值相同则阻止更新,避免不必要的渲染,或者使用PureReactComponent替代Component,其内部已经封装了shouldComponentUpdate的浅比较逻辑
  • 对于列表或其他结构相同的节点,为其中的每一项增加唯一key属性,以方便Reactdiff算法中对该节点的复用,减少节点的创建和删除操作
  • render函数中减少类似onClick={() => {doSomething()}}的写法,每次调用render函数时均会创建一个新的函数,即使内容没有发生任何变化,也会导致节点没必要的重渲染,建议将函数保存在组件的成员对象中,这样只会创建一次
  • 组件的props如果需要经过一系列运算后才能拿到最终结果,则可以考虑使用reselect库对结果进行缓存,如果props值未发生变化,则结果直接从缓存中拿,避免高昂的运算代价
  • webpack-bundle-analyzer分析当前页面的依赖包,是否存在不合理性,如果存在,找到优化点并进行优化

React 中 refs 的作用是什么

  • RefsReact 提供给我们的安全访问 DOM元素或者某个组件实例的句柄
  • 可以为元素添加ref属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回

用户不同权限 可以查看不同的页面 如何实现?

  1. Js方式undefined根据用户权限类型,把菜单配置成json, 没有权限的直接不显示
  2. react-router 方式 在route 标签上 添加onEnter事件,进入路由之前替换到首页
代码语言:javascript
复制
<Route path="/home" component={App} onEnter={(nexState,replace)=>{
      if(nexState.location.pathname!=='/'){
         var  sid = UtilsMoudle.getSidFromUrl(nexState);
         if(!sid){
            replace("/")
         }else{
            console.log(sid);
         }
      }
    }}>
  1. 自己封装一个privateRouter组件 里面判断是否有权限,有的话返回undefined<Route path={path} component={component} exact={exact}/>undefined没有权限的话component 返回一个提示信息的组件。
  2. 扩展一下,如果是根据用权限来判断是否隐藏组件该怎么做呢?undefinedreact 可以使用高阶组件,在高阶组件里面判断是否有权限,然后判断是否返回组件,无权限返回nullundefinedvue 可以使用自定义指令,如果没有权限移除组件
代码语言:javascript
复制
// 需要在入口处添加自定义权限指令v-auth,显示可操作组件
Vue.directive('auth', {
    bind: function (el, binding, vnode) {
        // 用户权限表
        const rules = auths
        for (let i = 0; i < rules.length; i++) {
            const item = rules[i]
            if(!binding.value || (binding.value == item.auth)){
                // 权限允许则显示组件
                return true
            }
        }
        // 移除组件
        el.parentNode.removeChild(el)
    }
})
// 使用
<template>
  <div>
    <Button v-auth="admin_user_add">添加用户</Button>
    <Button v-auth="admin_user_del">删除用户</Button>
    <Button v-auth="admin_user_edit">编辑用户</Button>
  </div>
</template>

React 数据持久化有什么实践吗?

封装数据持久化组件:

代码语言:javascript
复制
let storage={
    // 增加
    set(key, value){
        localStorage.setItem(key, JSON.stringify(value));
    },
    // 获取
    get(key){
        return JSON.parse(localStorage.getItem(key));
    },
    // 删除
    remove(key){
        localStorage.removeItem(key);
    }
};
export default Storage;

在React项目中,通过redux存储全局数据时,会有一个问题,如果用户刷新了网页,那么通过redux存储的全局数据就会被全部清空,比如登录信息等。这时就会有全局数据持久化存储的需求。首先想到的就是localStorage,localStorage是没有时间限制的数据存储,可以通过它来实现数据的持久化存储。

但是在已经使用redux来管理和存储全局数据的基础上,再去使用localStorage来读写数据,这样不仅是工作量巨大,还容易出错。那么有没有结合redux来达到持久数据存储功能的框架呢?当然,它就是redux-persist。redux-persist会将redux的store中的数据缓存到浏览器的localStorage中。其使用步骤如下:

(1)首先要安装redux-persist:

代码语言:javascript
复制
npm i redux-persist

(2)对于reducer和action的处理不变,只需修改store的生成代码,修改如下:

代码语言:javascript
复制
import {createStore} from 'redux'
import reducers from '../reducers/index'
import {persistStore, persistReducer} from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const persistConfig = {
    key: 'root',
    storage: storage,
    stateReconciler: autoMergeLevel2 // 查看 'Merge Process' 部分的具体情况
};
const myPersistReducer = persistReducer(persistConfig, reducers)
const store = createStore(myPersistReducer)
export const persistor = persistStore(store)
export default store

(3)在index.js中,将PersistGate标签作为网页内容的父标签:

代码语言:javascript
复制
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux'
import store from './redux/store/store'
import {persistor} from './redux/store/store'
import {PersistGate} from 'redux-persist/lib/integration/react';
ReactDOM.render(<Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
                {/*网页内容*/}            </PersistGate>
        </Provider>, document.getElementById('root'));

这就完成了通过redux-persist实现React持久化本地数据存储的简单应用。

在生命周期中的哪一步你应该发起 AJAX 请求

我们应当将AJAX 请求放到 componentDidMount 函数中执行,主要原因有下

  • React 下一代调和算法 Fiber 会通过开始或停止渲染的方式优化应用性能,其会影响到 componentWillMount 的触发次数。对于 componentWillMount 这个生命周期函数的调用次数会变得不确定,React 可能会多次频繁调用 componentWillMount。如果我们将 AJAX 请求放到 componentWillMount 函数中,那么显而易见其会被触发多次,自然也就不是好的选择。
  • 如果我们将AJAX 请求放置在生命周期的其他函数中,我们并不能保证请求仅在组件挂载完毕后才会要求响应。如果我们的数据请求在组件挂载之前就完成,并且调用了setState函数将数据添加到组件状态中,对于未挂载的组件则会报错。而在 componentDidMount 函数中进行 AJAX 请求则能有效避免这个问题

react有什么优点

  • 提高应用性能
  • 可以方便的在客户端和服务端使用
  • 使用jsx模板进行数据渲染,可读性好

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 解释 React 中 render() 的目的。
  • React中constructor和getInitialState的区别?
  • 对React-Fiber的理解,它解决了什么问题?
  • 在 React 中,何为 state
  • React.Component 和 React.PureComponent 的区别
  • 除了在构造函数中绑定 this,还有其它方式吗
  • 调用 setState 之后发生了什么
  • react-redux 的实现原理?
    • react中的Portal是什么?
      • 说说 React组件开发中关于作用域的常见问题。
        • Component, Element, Instance 之间有什么区别和联系?
          • 为什么要使用 React. Children. map( props. children,( )=>)而不是props. children. map ( ( ) => )?
            • 何为 Children
              • 简述react事件机制
              • React实现的移动应用中,如果出现卡顿,有哪些可以考虑的优化方案
              • React 中 refs 的作用是什么
                • 用户不同权限 可以查看不同的页面 如何实现?
                  • React 数据持久化有什么实践吗?
                  • 在生命周期中的哪一步你应该发起 AJAX 请求
                    • react有什么优点
                    相关产品与服务
                    对象存储
                    对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档