前端面试题 —— React (三)

目录

[一、对componentWillReceiveProps 的理解](#一、对componentWillReceiveProps 的理解)

二、React.forwardRef是什么?它有什么作用?

三、可以使用TypeScript写React应用吗?怎么操作?

[(1)如果还未创建 Create React App 项目](#(1)如果还未创建 Create React App 项目)

[(2)如果已经创建了 Create React App 项目,需要将 typescript 引入到已有项目中](#(2)如果已经创建了 Create React App 项目,需要将 typescript 引入到已有项目中)

四、React中constructor和getInitialState的区别?

五、React的严格模式如何使用,有什么用处?

六、为什么使用jsx的组件中没有看到使用react却需要引入react?

[七、HOC相比 mixins 有什么优点?](#七、HOC相比 mixins 有什么优点?)

[八、React 中的高阶组件运用了什么设计模式?](#八、React 中的高阶组件运用了什么设计模式?)

九、React-Router怎么设置重定向?

[十、Redux 请求中间件如何处理并发](#十、Redux 请求中间件如何处理并发)

使用redux-Saga

takeEvery

takeLatest

[十一、Redux 中间件是怎么拿到store 和 action? 然后怎么处理?](#十一、Redux 中间件是怎么拿到store 和 action? 然后怎么处理?)

十一、React中的setState和replaceState的区别是什么?

(1)setState()

(2)replaceState()


一、对componentWillReceiveProps 的理解

该方法当 props 发生变化时执行,初始化 render 时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用 this.setState() 来更新你的组件状态,旧的属性还是可以通过 this.props 来获取,这里调用更新状态是安全的,并不会触发额外的 render 调用。

使用好处:在这个生命周期中,可以在子组件的render函数执行前获取新的props,从而更新子组件自己的state。 可以将数据请求放在这里进行执行,需要传的参数则从componentWillReceiveProps(nextProps)中获取。而不必将所有的请求都放在父组件中。于是该请求只会在该组件渲染时才会发出,从而减轻请求负担。componentWillReceiveProps在初始化render的时候不会执行,它会在Component接受到新的状态(Props)时被触发,一般用于父组件状态更新时子组件的重新渲染。

二、React.forwardRef是什么?它有什么作用?

React.forwardRef 会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中。这种技术并不常见,但在以下两种场景中特别有用:

  • 转发 refs 到 DOM 组件
  • 在高阶组件中转发 refs

三、可以使用TypeScript写React应用吗?怎么操作?

(1)如果还未创建 Create React App 项目
  • 直接创建一个具有 typescript 的 Create React App 项目:
TypeScript 复制代码
 npx create-react-app demo --typescript
(2)如果已经创建了 Create React App 项目,需要将 typescript 引入到已有项目中
  • 通过命令将 typescript 引入项目:
javascript 复制代码
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
  • 将项目中任何 后缀名为 .js 的 JavaScript 文件重命名为 TypeScript 文件即后缀名为 .tsx(例如 src/index.js 重命名为 src/index.tsx )

四、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的严格模式如何使用,有什么用处?

StrictMode 是一个用来突出显示应用程序中潜在问题的工具。与 Fragment 一样,StrictMode 不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告。

可以为应用程序的任何部分启用严格模式。例如:

javascript 复制代码
import React from 'react';

function ExampleApplication() {
  return (
    <div>
      <Header />
      <React.StrictMode>       
        <div>
          <ComponentOne />
          <ComponentTwo />
        </div>
      </React.StrictMode>     
      <Footer />
    </div>
  );
}

在上述的示例中,不会对 Header 和 Footer 组件运行严格模式检查。但是,ComponentOne 和 ComponentTwo 以及它们的所有后代元素都将进行检查。

StrictMode 目前有助于:

  • 识别不安全的生命周期
  • 关于使用过时字符串 ref API 的警告
  • 关于使用废弃的 findDOMNode 方法的警告
  • 检测意外的副作用
  • 检测过时的 context API

六、为什么使用jsx的组件中没有看到使用react却需要引入react?

本质上来说JSX是React.createElement(component, props, ...children)方法的语法糖。在React 17之前,如果使用了JSX,其实就是在使用React, babel 会把组件转换为 CreateElement 形式。在React 17之后,就不再需要引入,因为 babel 已经可以帮我们自动引入react。

七、HOC相比 mixins 有什么优点?

HOC 和 Vue 中的 mixins 作用是一致的,并且在早期 React 也是使用 mixins 的方式。但是在使用 class 的方式创建组件以后,mixins 的方式就不能使用了,并且其实 mixins 也是存在一些问题的,比如:

  • 隐含了一些依赖,比如我在组件中写了某个 state 并且在 mixin 中使用了,就这存在了一个依赖关系。万一下次别人要移除它,就得去 mixin 中查找依赖。
  • 多个 mixin 中可能存在相同命名的函数,同时代码组件中也不能出现相同命名的函数,否则就是重写了。
  • 雪球效应,虽然我一个组件还是使用着同一个 mixin,但是一个 mixin 会被多个组件使用,可能会存在需求使得 mixin 修改原本的函数或者新增更多的函数,这样可能就会产生一个维护成本。

HOC 解决了这些问题,并且它们达成的效果也是一致的,同时也更加的政治正确(毕竟更加函数式了)。

八、React 中的高阶组件运用了什么设计模式?

使用了装饰模式,高阶组件的运用:

javascript 复制代码
function withWindowWidth(BaseComponent) {
  class DerivedClass extends React.Component {
    state = {
      windowWidth: window.innerWidth,
    }
    onResize = () => {
      this.setState({
        windowWidth: window.innerWidth,
      })
    }
    componentDidMount() {
      window.addEventListener('resize', this.onResize)
    }
    componentWillUnmount() {
      window.removeEventListener('resize', this.onResize);
    }
    render() {
      return <BaseComponent {...this.props} {...this.state}/>
    }
  }
  return DerivedClass;
}
const MyComponent = (props) => {
  return <div>Window width is: {props.windowWidth}</div>
};
export default withWindowWidth(MyComponent);

装饰模式的特点是不需要改变 被装饰对象 本身,而只是在外面套一个外壳接口。JavaScript 目前已经有了原生装饰器的提案,其用法如下:

javascript 复制代码
@testable
   class MyTestableClass {
}

九、React-Router怎么设置重定向?

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

html 复制代码
<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:若为真,重定向操作将会把新地址加入到访问历史记录里面,并且无法回退到前面的页面。

十、Redux 请求中间件如何处理并发

使用redux-Saga

redux-saga是一个管理redux应用异步操作的中间件,用于代替 redux-thunk 的。它通过创建 Sagas 将所有异步操作逻辑存放在一个地方进行集中处理,以此将react中的同步操作与异步操作区分开来,以便于后期的管理与维护。 redux-saga如何处理并发:

takeEvery

可以让多个 saga 任务并行被 fork 执行。

javascript 复制代码
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 就会非常有用。

javascript 复制代码
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))
    }
})

十一、Redux 中间件是怎么拿到store 和 action? 然后怎么处理?

redux中间件本质就是一个函数柯里化。redux applyMiddleware Api 源码中每个middleware 接受2个参数, Store 的getState 函数和dispatch 函数,分别获得store和action,最终返回一个函数。该函数会被传入 next 的下一个 middleware 的 dispatch 方法,并返回一个接收 action 的新函数,这个函数可以直接调用 next(action),或者在其他需要的时刻调用,甚至根本不去调用它。调用链中最后一个 middleware 会接受真实的 store的 dispatch 方法作为 next 参数,并借此结束调用链。所以,middleware 的函数签名是({ getState,dispatch })=> next => action。

十一、React中的setState和replaceState的区别是什么?

(1)setState()

setState()用于设置状态对象,其语法如下:

javascript 复制代码
setState(object nextState[, function callback])
  • nextState,将要设置的新状态,该状态会和当前的state合并。
  • callback,可选参数,回调函数。该函数会在setState设置成功,且组件重新渲染后调用。

合并nextState和当前state,并重新渲染组件。setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。

(2)replaceState()

replaceState()方法与setState()类似,但是方法只会保留nextState中状态,原state不在nextState中的状态都会被删除。其语法如下:

javascript 复制代码
replaceState(object nextState[, function callback])
  • nextState,将要设置的新状态,该状态会替换当前的state。
  • callback,可选参数,回调函数。该函数会在replaceState设置成功,且组件重新渲染后调用。

**总结:**setState 是修改其中的部分状态,相当于 Object.assign,只是覆盖,不会减少原来的状态。而replaceState 是完全替换原来的状态,相当于赋值,将原来的 state 替换为另一个对象,如果新状态属性减少,那么 state 中就没有这个状态了。

相关推荐
困顿小狗1 小时前
vue2 项目webpack 4升5
前端·webpack
sleeppingfrog1 小时前
vue3中自定义组件的双向绑定
前端·javascript·vue.js
Domain-zhuo2 小时前
uniapp 应用的生命周期、页面的生命周期、组件的生命周期
前端·javascript·vue.js·前端框架·uni-app·html·ecmascript
旅行中的伊蕾娜2 小时前
uniapp炫酷导航按钮及轮播指示器组件
前端·javascript·vue.js·微信小程序·uni-app
Liberty_yes2 小时前
uniapp navigateTo、redirectTo、reLaunch等页面路由跳转方法的区别
前端·uni-app
cy玩具2 小时前
Vuex在uniapp中的使用
开发语言·javascript·ecmascript
TWenYuan2 小时前
vue响应式数据-修改对象的属性值,视图不更新
前端·javascript·vue.js
振华OPPO2 小时前
VS Code使用NPM脚本启动Vue程序
前端·vue.js·vscode·npm·node.js·vue
乐茵安全3 小时前
基于python对pdf文件进行加密等操作
java·前端·python
超爱吃士力架3 小时前
设计模式五大基本原则
前端·后端·设计模式