乐趣区

关于react.js:校招前端二面常考react面试题边面边更

高阶组件

高阶函数:如果一个函数 承受一个或多个函数作为参数或者返回一个函数 就可称之为 高阶函数

高阶组件:如果一个函数 承受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件

react 中的高阶组件

React 中的高阶组件次要有两种模式:属性代理 反向继承

属性代理 Proxy

  • 操作 props
  • 抽离 state
  • 通过 ref 拜访到组件实例
  • 用其余元素包裹传入的组件 WrappedComponent

反向继承

会发现其属性代理和反向继承的实现有些相似的中央,都是返回一个继承了某个父类的子类,只不过属性代理中继承的是 React.Component,反向继承中继承的是传入的组件 WrappedComponent

反向继承能够用来做什么:

1. 操作 state

高阶组件中能够读取、编辑和删除 WrappedComponent 组件实例中的 state。甚至能够减少更多的state 项,然而 十分不倡议这么做 因为这可能会导致 state 难以保护及治理。

function withLogging(WrappedComponent) {    
    return class extends WrappedComponent {render() {    
            return (    
                <div>;    
                    <h2>;Debugger Component Logging...<h2>;    
                    <p>;state:<p>;    
                    <pre>;{JSON.stringify(this.state, null, 4)}<pre>;    
                    <p>props:<p>;    
                    <pre>{JSON.stringify(this.props, null, 4)}<pre>;    
                    {super.render()}    
                <div>;    
            );    
        }    
    };    
}

2. 渲染劫持(Render Highjacking)

条件渲染通过 props.isLoading 这个条件来判断渲染哪个组件。

批改由 render() 输入的 React 元素树

什么是状态晋升

应用 react 常常会遇到几个组件须要共用状态数据的状况。这种状况下,咱们最好将这部分共享的状态晋升至他们最近的父组件当中进行治理。咱们来看一下具体如何操作吧。

import React from 'react'
class Child_1 extends React.Component{constructor(props){super(props)
    }
    render(){
        return (
            <div>
                <h1>{this.props.value+2}</h1>
            </div> 
        )
    }
}
class Child_2 extends React.Component{constructor(props){super(props)
    }
    render(){
        return (
            <div>
                <h1>{this.props.value+1}</h1>
            </div> 
        )
    }
}
class Three extends React.Component {constructor(props){super(props)
        this.state = {txt:"牛逼"}
        this.handleChange = this.handleChange.bind(this)
    }
    handleChange(e){
        this.setState({txt:e.target.value})
    }
    render(){
       return (
            <div>
                <input type="text" value={this.state.txt} onChange={this.handleChange}/>
                <p>{this.state.txt}</p>
                <Child_1 value={this.state.txt}/>
                <Child_2 value={this.state.txt}/>
            </div>
       )
    }
}
export default Three

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

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

在结构函数调用 super 并将 props 作为参数传入的作用是啥?

在调用 super() 办法之前,子类构造函数无奈应用 this 援用,ES6 子类也是如此。将 props 参数传递给 super() 调用的次要起因是在子构造函数中可能通过 this.props 来获取传入的 props
传递 props

class MyComponent extends React.Component {constructor(props) {super(props);
    console.log(this.props); // {name: 'sudheer',age: 30}
  }
}

没传递 props

class MyComponent extends React.Component {constructor(props) {super();
    console.log(this.props); // undefined
    // 然而 Props 参数依然可用
    console.log(props); // Prints {name: 'sudheer',age: 30}
  }
  render() {
    // 构造函数内部不受影响
    console.log(this.props); // {name: 'sudheer',age: 30}
  }
}

下面示例揭示了一点。props 的行为只有在构造函数中是不同的,在构造函数之外也是一样的。

Redux 申请中间件如何解决并发

应用 redux-Saga redux-saga 是一个治理 redux 利用异步操作的中间件,用于代替 redux-thunk 的。它通过创立 Sagas 将所有异步操作逻辑寄存在一个中央进行集中处理,以此将 react 中的同步操作与异步操作辨别开来,以便于前期的治理与保护。redux-saga 如何解决并发:

  • takeEvery

能够让多个 saga 工作并行被 fork 执行。

import {
    fork,
    take
} from "redux-saga/effects"

const takeEvery = (pattern, saga, ...args) => fork(function*() {while (true) {const action = yield take(pattern)
        yield fork(saga, ...args.concat(action))
    }
})
  • takeLatest

takeLatest 不容许多个 saga 工作并行地执行。一旦接管到新的发动的 action,它就会勾销后面所有 fork 过的工作(如果这些工作还在执行的话)。
在解决 AJAX 申请的时候,如果只心愿获取最初那个申请的响应,takeLatest 就会十分有用。

import {
    cancel,
    fork,
    take
} from "redux-saga/effects"

const takeLatest = (pattern, saga, ...args) => fork(function*() {
    let lastTask
    while (true) {const action = yield take(pattern)
        if (lastTask) {yield cancel(lastTask) // 如果工作曾经完结,则 cancel 为空操作
        }
        lastTask = yield fork(saga, ...args.concat(action))
    }
})

什么是 state

  • 在组件初始化的时候 通过 this.state 给组件设置一个初始化的 state,第一次 render 的时候会用 state 来渲染组件
  • 通过 this.setState 办法来更新 state

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

为何 React 事件要本人绑定 this

在 React 源码中,当具体到某一事件处理函数将要调用时,将调用 invokeGuardedCallback 办法。

function invokeGuardedCallback(name, func, a) {
  try {func(a);
  } catch (x) {if (caughtError === null) {caughtError = x;}
  }
}

事件处理函数是间接调用的,并没有指定调用的组件,所以不进行手动绑定的状况下间接获取到的 this 是不精确的,所以咱们须要手动将以后组件绑定到 this 上

(组件的)状态 (state) 和属性 (props) 之间有何不同

State 是一种数据结构,用于组件挂载时所需数据的默认值。State 可能会随着工夫的推移而产生渐变,但少数时候是作为用户事件行为的后果。

Props(properties 的简写)则是组件的配置。props 由父组件传递给子组件,并且就子组件而言,props 是不可变的(immutable)。组件不能扭转本身的 props,然而能够把其子组件的 props 放在一起(对立治理)。Props 也不仅仅是数据 – 回调函数也能够通过 props 传递。

为什么 React 元素有一个 $$typeof 属性

目标是为了避免 XSS 攻打。因为 Synbol 无奈被序列化,所以 React 能够通过有没有 $$typeof 属性来断出以后的 element 对象是从数据库来的还是本人生成的。

  • 如果没有 $$typeof 这个属性,react 会回绝解决该元素。
  • 在 React 的古老版本中,上面的写法会呈现 XSS 攻打:
// 服务端容许用户存储 JSON
let expectedTextButGotJSON = {
  type: 'div',
  props: {
    dangerouslySetInnerHTML: {__html: '/* 把你想的搁着 */'},
  },
  // ...
};
let message = {text: expectedTextButGotJSON};

// React 0.13 中有危险
<p>
  {message.text}
</p>

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

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

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

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

  • 分批延时对 DOM 进行操作,防止一次性操作大量 DOM 节点,能够失去更好的用户体验;
  • 给浏览器一点喘息的机会,它会对代码进行编译优化(JIT)及进行热代码优化,或者对 reflow 进行修改。

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

如何 React.createElement?

const element = <h1 className="greeting">Hello, world!</h1>;

上述代码如何应用 React.createElement 来实现:

const element = React.createElement("h1", { className: "greeting"}, "Hello, world!");

在 React 中如何处理事件

为了解决跨浏览器的兼容性问题,SyntheticEvent 实例将被传递给你的事件处理函数,SyntheticEvent是 React 跨浏览器的浏览器原生事件包装器,它还领有和浏览器原生事件雷同的接口,包含 stopPropagation()preventDefault()
比拟乏味的是,React 实际上并不将事件附加到子节点自身。React 应用单个事件侦听器侦听顶层的所有事件。这对性能有益处,也意味着 React 在更新 DOM 时不须要跟踪事件监听器。

React 如何辨别 Class 组件 和 Function 组件

个别的形式是借助 typeof 和 Function.prototype.toString 来判断以后是不是 class,如下:

function isClass(func) {
  return typeof func === 'function'
    && /^class\s/.test(Function.prototype.toString.call(func));
}

然而这个形式有它的局限性,因为如果用了 babel 等转换工具,将 class 写法全副转为 function 写法,下面的判断就会生效。

React 辨别 Class 组件 和 Function 组件的形式很奇妙,因为所有的类组件都要继承 React.Component,所以只有判断原型链上是否有 React.Component 就能够了:

AComponent.prototype instanceof React.Component

React 的生命周期办法有哪些?

  • componentWillMount: 在渲染之前执行,用于根组件中的 App 级配置。
  • componentDidMount:在第一次渲染之后执行,能够在这里做 AJAX 申请,DOM 的操作或状态更新以及设置事件监听器。
  • componentWillReceiveProps:在初始化 render 的时候不会执行,它会在组件承受到新的状态 (Props) 时被触发,个别用于父组件状态更新时子组件的从新渲染
  • shouldComponentUpdate:确定是否更新组件。默认状况下,它返回true。如果确定在 stateprops 更新后组件不须要在从新渲染,则能够返回false,这是一个进步性能的办法。
  • componentWillUpdate:在 shouldComponentUpdate 返回 true 确定要更新组件之前件之前执行。
  • componentDidUpdate:它次要用于更新 DOM 以响应 propsstate更改。
  • componentWillUnmount:它用于勾销任何的网络申请,或删除与组件关联的所有事件监听器。

类组件和函数组件之间的区别是啥?

  • 类组件 能够应用其余个性,如状态 state 和生命周期钩子。
  • 当组件只是接管 props 渲染到页面时,就是无状态组件,就属于函数组件,也被称为哑组件或展现组件。
    函数组件和类组件当然是有区别的,而且函数组件的性能比类组件的性能要高,因为类组件应用的时候要实例化,而函数组件间接执行函数取返回后果即可。为了进步性能,尽量应用函数组件。

    区别 函数组件 类组件
    是否有 this 没有
    是否有生命周期 没有
    是否有状态 state 没有

react-redux 的实现原理?

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

React-Router 怎么设置重定向?

应用 <Redirect> 组件实现路由的重定向:

<Switch>
  <Redirect from='/users/:id' to='/users/profile/:id'/>
  <Route path='/users/profile/:id' component={Profile}/>
</Switch>

当申请 /users/:id 被重定向去 '/users/profile/:id'

  • 属性 from: string:须要匹配的将要被重定向门路。
  • 属性 to: string:重定向的 URL 字符串
  • 属性 to: object:重定向的 location 对象
  • 属性 push: bool:若为真,重定向操作将会把新地址退出到拜访历史记录外面,并且无奈回退到后面的页面。

对 React Hook 的了解,它的实现原理是什么

React-Hooks 是 React 团队在 React 组件开发实际中,逐步认知到的一个改良点,这背地其实波及对 类组件 函数组件 两种组件模式的思考和偏重。

(1)类组件: 所谓类组件,就是基于 ES6 Class 这种写法,通过继承 React.Component 得来的 React 组件。以下是一个类组件:

class DemoClass extends React.Component {
  state = {text: ""};
  componentDidMount() {//...}
  changeText = (newText) => {
    this.setState({text: newText});
  };

  render() {
    return (
      <div className="demoClass">
        <p>{this.state.text}</p>
        <button onClick={this.changeText}> 批改 </button>
      </div>
    );
  }
}

能够看出,React 类组件外部预置了相当多的“现成的货色”等着咱们去调度 / 定制,state 和生命周期就是这些“现成货色”中的典型。要想得到这些货色,难度也不大,只须要继承一个 React.Component 即可。

当然,这也是类组件的一个不便,它太繁冗了,对于解决许多问题来说,编写一个类组件切实是一个过于简单的姿态。简单的姿态必然带来昂扬的了解老本,这也是咱们所不想看到的。除此之外,因为开发者编写的逻辑在封装后是和组件粘在一起的,这就使得 类组件外部的逻辑难以实现拆分和复用。

(2)函数组件:函数组件就是以函数的状态存在的 React 组件。晚期并没有 React-Hooks,函数组件外部无奈定义和保护 state,因而它还有一个别名叫“无状态组件”。以下是一个函数组件:

function DemoFunction(props) {const { text} = props
  return (
    <div className="demoFunction">
      <p>{` 函数组件接管的内容:[${text}]`}</p>
    </div>
  );
}

相比于类组件,函数组件肉眼可见的特质天然包含轻量、灵便、易于组织和保护、较低的学习老本等。

通过比照,从状态上能够对两种组件做辨别,它们之间的区别如下:

  • 类组件须要继承 class,函数组件不须要;
  • 类组件能够拜访生命周期办法,函数组件不能;
  • 类组件中能够获取到实例化后的 this,并基于这个 this 做各种各样的事件,而函数组件不能够;
  • 类组件中能够定义并保护 state(状态),而函数组件不能够;

除此之外,还有一些其余的不同。通过下面的区别,咱们不能说谁好谁坏,它们各有本人的劣势。在 React-Hooks 呈现之前,类组件的能力边界显著强于函数组件。

实际上,类组件和函数组件之间,是面向对象和函数式编程这两套不同的设计思维之间的差别。而函数组件更加符合 React 框架的设计理念:React 组件自身的定位就是函数,一个输出数据、输入 UI 的函数。作为开发者,咱们编写的是申明式的代码,而 React 框架的次要工作,就是及时地把申明式的代码转换为命令式的 DOM 操作,把数据层面的形容映射到用户可见的 UI 变动中去。这就意味着从原则上来讲,React 的数据应该总是紧紧地和渲染绑定在一起的,而类组件做不到这一点。函数组件就真正地将数据和渲染绑定到了一起。函数组件是一个更加匹配其设计理念、也更有利于逻辑拆分与重用的组件表达形式。

为了能让开发者更好的的去编写函数式组件。于是,React-Hooks 便应运而生。

React-Hooks 是一套可能使函数组件更弱小、更灵便的“钩子”。

函数组件比起类组件少了很多货色,比方生命周期、对 state 的治理等。这就给函数组件的应用带来了十分多的局限性,导致咱们并不能应用函数这种模式,写出一个真正的全功能的组件。而 React-Hooks 的呈现,就是为了帮忙函数组件补齐这些(绝对于类组件来说)缺失的能力。

如果说函数组件是一台笨重的快艇,那么 React-Hooks 就是一个内容丰盛的零部件箱。“重装战舰”所预置的那些设施,这个箱子里根本全都有,同时它还不强制你全都要,而是容许你自在地抉择和应用你须要的那些能力,而后将这些能力以 Hook(钩子)的模式“钩”进你的组件里,从而定制出一个最适宜你的“专属战舰”。

什么是 React Context?

Context 通过组件树提供了一个传递数据的办法,从而防止了在每一个层级手动的传递 props 属性。

如何用 React 构建(build)生产模式?

通常,应用 Webpack 的 DefinePlugin 办法将 NODE ENV 设置为 production。这将剥离 propType 验证和额定的正告。除此之外,还能够缩小代码,因为 React 应用 Uglify 的 dead-code 来打消开发代码和正文,这将大大减少包占用的空间。

退出移动版