关于前端:社招前端常见react面试题必备

6次阅读

共计 8298 个字符,预计需要花费 21 分钟才能阅读完成。

解释 React 中 render() 的目标。

每个 React 组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的示意。如果须要渲染多个 HTML 元素,则必须将它们组合在一个关闭标记内,例如 <form><group><div> 等。此函数必须放弃污浊,即必须每次调用时都返回雷同的后果。

React 中 constructor 和 getInitialState 的区别?

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

getInitialState 是 ES5 中的办法,如果应用 createClass 办法创立一个 Component 组件,能够主动调用它的 getInitialState 办法来获取初始化的 State 对象,

var APP = React.creatClass ({getInitialState() {
    return { 
        userName: 'hi',
        userId: 0
     };
 }
})

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

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 元素。

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 将是一个数组。
以上面的代码为例。

<Parent>
    <h1> 有课前端网 </h1>
</Parent>

在父组件外部,如果尝试应用 props.children. map 映射子对象,则会抛出谬误,因为 props. children 是一个对象,而不是一个数组。
如果有多个子元素,React 会使 props.children 成为一个数组,如下所示。

<Parent>
  <h1> 有课前端网 </h1>
  <h2> 前端技术学习平台 </h2>
</Parent>;
// 不倡议应用如下形式,在这个案例中会抛出谬误。class Parent extends Component {render() {return <div> {this.props.children.map((obj) => obj)}</div>;
  }
}

倡议应用如下形式,防止在上一个案例中抛出谬误。

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 形式
    依据用户权限类型,把菜单配置成 json, 没有权限的间接不显示
  2. react-router 形式 在 route 标签上 增加 onEnter 事件,进入路由之前替换到首页
<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 组件 外面判断是否有权限,有的话返回
    <Route path={path} component={component} exact={exact}/>
    没有权限的话 component 返回一个提示信息的组件。
  2. 扩大一下,如果是依据用权限来判断是否暗藏组件该怎么做呢?
    react 能够应用高阶组件,在高阶组件外面判断是否有权限,而后判断是否返回组件,无权限返回 null
    vue 能够应用自定义指令,如果没有权限移除组件
// 须要在入口处增加自定义权限指令 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 数据长久化有什么实际吗?

封装数据长久化组件:

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:

npm i redux-persist

(2)对于 reducer 和 action 的解决不变,只需批改 store 的生成代码,批改如下:

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 标签作为网页内容的父标签:

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 模板进行数据渲染,可读性好
正文完
 0