关于前端:前端一面必会react面试题边面边更

React setState 调用之后产生了什么?是同步还是异步?

(1)React中setState后产生了什么

在代码中调用setState函数之后,React 会将传入的参数对象与组件以后的状态合并,而后触发和谐过程(Reconciliation)。通过和谐过程,React 会以绝对高效的形式依据新的状态构建 React 元素树并且着手从新渲染整个UI界面。

在 React 失去元素树之后,React 会主动计算出新的树与老树的节点差别,而后依据差别对界面进行最小化重渲染。在差别计算算法中,React 可能绝对准确地晓得哪些地位产生了扭转以及应该如何扭转,这就保障了按需更新,而不是全副从新渲染。

如果在短时间内频繁setState。React会将state的扭转压入栈中,在适合的机会,批量更新state和视图,达到进步性能的成果。

(2)setState 是同步还是异步的

如果所有setState是同步的,意味着每执行一次setState时(有可能一个同步代码中,屡次setState),都从新vnode diff + dom批改,这对性能来说是极为不好的。如果是异步,则能够把一个同步代码中的多个setState合并成一次组件更新。所以默认是异步的,然而在一些状况下是同步的。

setState 并不是单纯同步/异步的,它的体现会因调用场景的不同而不同。在源码中,通过 isBatchingUpdates 来判断setState 是先存进 state 队列还是间接更新,如果值为 true 则执行异步操作,为 false 则间接更新。

  • 异步: 在 React 能够管制的中央,就为 true,比方在 React 生命周期事件和合成事件中,都会走合并操作,提早更新的策略。
  • 同步: 在 React 无法控制的中央,比方原生事件,具体就是在 addEventListener 、setTimeout、setInterval 等事件中,就只能同步更新。

个别认为,做异步设计是为了性能优化、缩小渲染次数:

  • setState设计为异步,能够显著的晋升性能。如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面从新渲染,这样效率是很低的;最好的方法应该是获取到多个更新,之后进行批量更新;
  • 如果同步更新了state,然而还没有执行render函数,那么stateprops不能放弃同步。stateprops不能放弃一致性,会在开发中产生很多的问题;

为什么应用jsx的组件中没有看到应用react却须要引入react?

实质上来说JSX是React.createElement(component, props, ...children)办法的语法糖。在React 17之前,如果应用了JSX,其实就是在应用React, babel 会把组件转换为 CreateElement 模式。在React 17之后,就不再须要引入,因为 babel 曾经能够帮咱们主动引入react。

React中有应用过getDefaultProps吗?它有什么作用?

通过实现组件的getDefaultProps,对属性设置默认值(ES5的写法):

var ShowTitle = React.createClass({
  getDefaultProps:function(){
    return{
      title : "React"
    }
  },
  render : function(){
    return <h1>{this.props.title}</h1>
  }
});

React 高阶组件、Render props、hooks 有什么区别,为什么要一直迭代

这三者是目前react解决代码复用的次要形式:

  • 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。具体而言,高阶组件是参数为组件,返回值为新组件的函数。
  • render props是指一种在 React 组件之间应用一个值为函数的 prop 共享代码的简略技术,更具体的说,render prop 是一个用于告知组件须要渲染什么内容的函数 prop。
  • 通常,render props 和高阶组件只渲染一个子节点。让 Hook 来服务这个应用场景更加简略。这两种模式仍有用武之地,(例如,一个虚构滚动条组件或者会有一个 renderltem 属性,或是一个可见的容器组件或者会有它本人的 DOM 构造)。但在大部分场景下,Hook 足够了,并且可能帮忙缩小嵌套。

(1)HOC 官网解释∶

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。

简言之,HOC是一种组件的设计模式,HOC承受一个组件和额定的参数(如果须要),返回一个新的组件。HOC 是纯函数,没有副作用。

// hoc的定义
function withSubscription(WrappedComponent, selectData) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        data: selectData(DataSource, props)
      };
    }
    // 一些通用的逻辑解决
    render() {
      // ... 并应用新数据渲染被包装的组件!
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };

// 应用
const BlogPostWithSubscription = withSubscription(BlogPost,
  (DataSource, props) => DataSource.getBlogPost(props.id));

HOC的优缺点∶

  • 长处∶ 逻辑服用、不影响被包裹组件的外部逻辑。
  • 毛病∶ hoc传递给被包裹组件的props容易和被包裹后的组件重名,进而被笼罩

(2)Render props 官网解释∶

“render prop”是指一种在 React 组件之间应用一个值为函数的 prop 共享代码的简略技术

具备render prop 的组件承受一个返回React元素的函数,将render的渲染逻辑注入到组件外部。在这里,”render”的命名能够是任何其余无效的标识符。

// DataProvider组件外部的渲染逻辑如下
class DataProvider extends React.Components {
     state = {
    name: 'Tom'
  }

    render() {
    return (
        <div>
          <p>共享数据组件本人外部的渲染逻辑</p>
          { this.props.render(this.state) }      </div>
    );
  }
}

// 调用形式
<DataProvider render={data => (
  <h1>Hello {data.name}</h1>
)}/>

由此能够看到,render props的优缺点也很显著∶

  • 长处:数据共享、代码复用,将组件内的state作为props传递给调用者,将渲染逻辑交给调用者。
  • 毛病:无奈在 return 语句外拜访数据、嵌套写法不够优雅

(3)Hooks 官网解释∶

Hook是 React 16.8 的新增个性。它能够让你在不编写 class 的状况下应用 state 以及其余的 React 个性。通过自定义hook,能够复用代码逻辑。

// 自定义一个获取订阅数据的hook
function useSubscription() {
  const data = DataSource.getComments();
  return [data];
}
// 
function CommentList(props) {
  const {data} = props;
  const [subData] = useSubscription();
    ...
}
// 应用
<CommentList data='hello' />

以上能够看出,hook解决了hoc的prop笼罩的问题,同时应用的形式解决了render props的嵌套天堂的问题。hook的长处如下∶

  • 应用直观;
  • 解决hoc的prop 重名问题;
  • 解决render props 因共享数据 而呈现嵌套天堂的问题;
  • 能在return之外应用数据的问题。

须要留神的是:hook只能在组件顶层应用,不可在分支语句中应用。、

React key 是干嘛用的 为什么要加?key 次要是解决哪一类问题的

Keys 是 React 用于追踪哪些列表中元素被批改、被增加或者被移除的辅助标识。在开发过程中,咱们须要保障某个元素的 key 在其同级元素中具备唯一性。

在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是早先创立的还是被挪动而来的元素,从而缩小不必要的元素重渲染此外,React 还须要借助 Key 值来判断元素与本地状态的关联关系。

注意事项:

  • key值肯定要和具体的元素—一对应;
  • 尽量不要用数组的index去作为key;
  • 不要在render的时候用随机数或者其余操作给元素加上不稳固的key,这样造成的性能开销比不加key的状况下更蹩脚。

setState之后 产生了什么?

  • (1)代码中调用 setState 函数之后,React 会将传入的参数对象与组件以后的状态合并,而后触发所谓的和谐过程(Reconciliation)。
  • (2)通过和谐过程,React 会以绝对高效的形式依据新的状态构建 React 元素树并且着手从新渲染整个 UI 界面;
  • (3)在 React 失去元素树之后,React 会主动计算出新的树与老树的节点差别,而后依据差别对界面进行最小化重渲染;
  • (4)在差别计算算法中,React 可能绝对准确地晓得哪些地位产生了扭转以及应该如何扭转,这就保障了按需更新,而不是全副从新渲染。

setState的调用会引起React的更新生命周期的4个函数执行。

shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

参考 前端进阶面试题具体解答

什么是 React Fiber?

Fiber 是 React 16 中新的协调引擎或从新实现外围算法。它的次要指标是反对虚构DOM的增量渲染。React Fiber 的指标是进步其在动画、布局、手势、暂停、停止或重用等方面的适用性,并为不同类型的更新调配优先级,以及新的并发原语。
React Fiber 的指标是加强其在动画、布局和手势等畛域的适用性。它的次要个性是增量渲染:可能将渲染工作宰割成块,并将其扩散到多个帧中。

react 生命周期

初始化阶段:

  • getDefaultProps:获取实例的默认属性
  • getInitialState:获取每个实例的初始化状态
  • componentWillMount:组件行将被装载、渲染到页面上
  • render:组件在这里生成虚构的 DOM 节点
  • componentDidMount:组件真正在被装载之后

运行中状态:

  • componentWillReceiveProps:组件将要接管到属性的时候调用
  • shouldComponentUpdate:组件承受到新属性或者新状态的时候(能够返回 false,接收数据后不更新,阻止 render 调用,前面的函数不会被继续执行了)
  • componentWillUpdate:组件行将更新不能批改属性和状态
  • render:组件从新描述
  • componentDidUpdate:组件曾经更新

销毁阶段:

  • componentWillUnmount:组件行将销毁

shouldComponentUpdate 是做什么的,(react 性能优化是哪个周期函数?)

shouldComponentUpdate 这个办法用来判断是否须要调用 render 办法从新描述 dom。因为 dom 的描述十分耗费性能,如果咱们能在 shouldComponentUpdate 办法中可能写出更优化的 dom diff 算法,能够极大的进步性能。

在react17 会删除以下三个生命周期
componentWillMount,componentWillReceiveProps , componentWillUpdate

对React的插槽(Portals)的了解,如何应用,有哪些应用场景

React 官网对 Portals 的定义:

Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优良的计划

Portals 是React 16提供的官网解决方案,使得组件能够脱离父组件层级挂载在DOM树的任何地位。艰深来讲,就是咱们 render 一个组件,但这个组件的 DOM 构造并不在本组件内。

Portals语法如下:

ReactDOM.createPortal(child, container);
  • 第一个参数 child 是可渲染的 React 子项,比方元素,字符串或者片段等;
  • 第二个参数 container 是一个 DOM 元素。

个别状况下,组件的render函数返回的元素会被挂载在它的父级组件上:

import DemoComponent from './DemoComponent';
render() {
  // DemoComponent元素会被挂载在id为parent的div的元素上
  return (
    <div id="parent">
        <DemoComponent />
    </div>
  );
}

然而,有些元素须要被挂载在更高层级的地位。最典型的利用场景:当父组件具备overflow: hidden或者z-index的款式设置时,组件有可能被其余元素遮挡,这时就能够思考要不要应用Portal使组件的挂载脱离父组件。例如:对话框,模态窗。

import DemoComponent from './DemoComponent';
render() {
  // DemoComponent元素会被挂载在id为parent的div的元素上
  return (
    <div id="parent">
        <DemoComponent />
    </div>
  );
}

React.Children.map和js的map有什么区别?

JavaScript中的map不会对为null或者undefined的数据进行解决,而React.Children.map中的map能够解决React.Children为null或者undefined的状况。

对 React context 的了解

在React中,数据传递个别应用props传递数据,维持单向数据流,这样能够让组件之间的关系变得简略且可预测,然而单项数据流在某些场景中并不实用。单纯一对的父子组件传递并无问题,但要是组件之间层层依赖深刻,props就须要层层传递显然,这样做太繁琐了。

Context 提供了一种在组件之间共享此类值的形式,而不用显式地通过组件树的逐层传递 props。

能够把context当做是特定一个组件树内共享的store,用来做数据传递。简略说就是,当你不想在组件树中通过逐层传递props或者state的形式来传递数据时,能够应用Context来实现跨层级的组件数据传递。

JS的代码块在执行期间,会创立一个相应的作用域链,这个作用域链记录着运行时JS代码块执行期间所能拜访的流动对象,包含变量和函数,JS程序通过作用域链拜访到代码块外部或者内部的变量和函数。

如果以JS的作用域链作为类比,React组件提供的Context对象其实就好比一个提供给子组件拜访的作用域,而 Context对象的属性能够看成作用域上的流动对象。因为组件 的 Context 由其父节点链上所有组件通 过 getChildContext()返回的Context对象组合而成,所以,组件通过Context是能够拜访到其父组件链上所有节点组件提供的Context的属性。

React中refs的作用是什么?有哪些利用场景?

Refs 提供了一种形式,用于拜访在 render 办法中创立的 React 元素或 DOM 节点。Refs 应该审慎应用,如下场景应用 Refs 比拟适宜:

  • 解决焦点、文本抉择或者媒体的管制
  • 触发必要的动画
  • 集成第三方 DOM 库

Refs 是应用 React.createRef() 办法创立的,他通过 ref 属性附加到 React 元素上。要在整个组件中应用 Refs,须要将 ref 在构造函数中调配给其实例属性:

class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
  }
  render() {
    return <div ref={this.myRef} />
  }
}

因为函数组件没有实例,因而不能在函数组件上间接应用 ref

function MyFunctionalComponent() {
  return <input />;
}
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }
  render() {
    // 这将不会工作!
    return (
      <MyFunctionalComponent ref={this.textInput} />
    );
  }
}

但能够通过闭合的帮忙在函数组件外部进行应用 Refs:

function CustomTextInput(props) {
  // 这里必须申明 textInput,这样 ref 回调才能够援用它
  let textInput = null;
  function handleClick() {
    textInput.focus();
  }
  return (
    <div>
      <input
        type="text"
        ref={(input) => { textInput = input; }} />      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );  
}

留神:

  • 不应该适度的应用 Refs
  • ref 的返回值取决于节点的类型:

    • ref 属性被用于一个一般的 HTML 元素时,React.createRef() 将接管底层 DOM 元素作为他的 current 属性以创立 ref
    • ref 属性被用于一个自定义的类组件时,ref 对象将接管该组件已挂载的实例作为他的 current
  • 当在父组件中须要拜访子组件中的 ref 时可应用传递 Refs 或回调 Refs。

在React中遍历的办法有哪些?

(1)遍历数组:map && forEach

import React from 'react';

class App extends React.Component {
  render() {
    let arr = ['a', 'b', 'c', 'd'];
    return (
      <ul>
        {
          arr.map((item, index) => {
            return <li key={index}>{item}</li>
          })
        }
      </ul>
    )
  }
}

class App extends React.Component {
  render() {
    let arr = ['a', 'b', 'c', 'd'];
    return (
      <ul>
        {
          arr.forEach((item, index) => {
            return <li key={index}>{item}</li>
          })
        }
      </ul>
    )
  }
}

(2)遍历对象:map && for in

class App extends React.Component {
  render() {
    let obj = {
      a: 1,
      b: 2,
      c: 3
    }
    return (
      <ul>
        {
          (() => {
            let domArr = [];
            for(const key in obj) {
              if(obj.hasOwnProperty(key)) {
                const value = obj[key]
                domArr.push(<li key={key}>{value}</li>)
              }
            }
            return domArr;
          })()
        }
      </ul>
    )
  }
}

// Object.entries() 把对象转换成数组
class App extends React.Component {
  render() {
    let obj = {
      a: 1,
      b: 2,
      c: 3
    }
    return (
      <ul>
        {
          Object.entries(obj).map(([key, value], index) => {   // item是一个数组,把item解构,写法是[key, value]
            return <li key={key}>{value}</li>
          }) 
        }
      </ul>
    )
  }
}

传入 setState 函数的第二个参数的作用是什么?

该函数会在 setState 函数调用实现并且组件开始重渲染的时候被调用,咱们能够用该函数来监听渲染是否实现:

this.setState(
  { username: 'tylermcginnis33' },
  () => console.log('setState has finished and the component has re-rendered.')
)
this.setState((prevState, props) => {
  return {
    streak: prevState.streak + props.count
  }
})

class类的key改了,会产生什么,会执行哪些周期函数?

在开发过程中,咱们须要保障某个元素的 key 在其同级元素中具备唯一性。在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是早先创立的还是被挪动而来的元素,从而缩小不必要的元素重渲染。此外,React 还须要借助 Key 值来判断元素与本地状态的关联关系,因而咱们绝不可漠视转换函数中 Key 的重要性。

答:componentWillMount componentDidMount render

React中的状态是什么?它是如何应用的

状态是 React 组件的外围,是数据的起源,必须尽可能简略。基本上状态是确定组件出现和行为的对象。与props 不同,它们是可变的,并创立动静和交互式组件。能够通过 this.state() 拜访它们。

React的Fiber工作原理,解决了什么问题

  • React Fiber 是一种基于浏览器的单线程调度算法。

React Fiber 用相似 requestIdleCallback 的机制来做异步 diff。然而之前数据结构不反对这样的实现异步 diff,于是 React 实现了一个相似链表的数据结构,将原来的 递归diff 变成了当初的 遍历diff,这样就能做到异步可更新了

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长久化本地数据存储的简略利用。

React中props.children和React.Children的区别

在React中,当波及组件嵌套,在父组件中应用props.children把所有子组件显示进去。如下:

function ParentComponent(props){
    return (
        <div>
            {props.children}        </div>
    )
}

如果想把父组件中的属性传给所有的子组件,须要应用React.Children办法。

比方,把几个Radio组合起来,合成一个RadioGroup,这就要求所有的Radio具备同样的name属性值。能够这样:把Radio看做子组件,RadioGroup看做父组件,name的属性值在RadioGroup这个父组件中设置。

首先是子组件:

//子组件
function RadioOption(props) {
  return (
    <label>
      <input type="radio" value={props.value} name={props.name} />
      {props.label}    </label>
  )
}

而后是父组件,不仅须要把它所有的子组件显示进去,还须要为每个子组件赋上name属性和值:

//父组件用,props是指父组件的props
function renderChildren(props) {

  //遍历所有子组件
  return React.Children.map(props.children, child => {
    if (child.type === RadioOption)
      return React.cloneElement(child, {
        //把父组件的props.name赋值给每个子组件
        name: props.name
      })
    else
      return child
  })
}
//父组件
function RadioGroup(props) {
  return (
    <div>
      {renderChildren(props)}    </div>
  )
}
function App() {
  return (
    <RadioGroup name="hello">
      <RadioOption label="选项一" value="1" />
      <RadioOption label="选项二" value="2" />
      <RadioOption label="选项三" value="3" />
    </RadioGroup>
  )
}
export default App;

以上,React.Children.map让咱们对父组件的所有子组件又更灵便的管制。

在 React中元素( element)和组件( component)有什么区别?

简略地说,在 React中元素(虛拟DOM)形容了你在屏幕上看到的DOM元素。
换个说法就是,在 React中元素是页面中DOM元素的对象示意形式。在 React中组件是一个函数或一个类,它能够承受输出并返回一个元素。
留神:工作中,为了进步开发效率,通常应用JSX语法示意 React元素(虚构DOM)。在编译的时候,把它转化成一个 React. createElement调用办法。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理