关于react.js:一天梳理React面试高频知识点

46次阅读

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

怎么用 React.createElement 重写上面的代码

Question:

const element = (
  <h1 className="greeting">
    Hello, rdhub.cn!
  </h1>
);

Answer:

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, rdhub.cn!'
);

对 React-Intl 的了解,它的工作原理?

React-intl 是雅虎的语言国际化开源我的项目 FormatJS 的一部分,通过其提供的组件和 API 能够与 ReactJS 绑定。

React-intl 提供了两种应用办法,一种是援用 React 组件,另一种是间接调取 API,官网更加举荐在 React 我的项目中应用前者,只有在无奈应用 React 组件的中央,才应该调用框架提供的 API。它提供了一系列的 React 组件,包含数字格式化、字符串格式化、日期格式化等。

在 React-intl 中,能够配置不同的语言包,他的工作原理就是依据须要,在语言包之间进行切换。

react 有什么特点

  • react 应用过的虚构 DOM,而不是实在 DOM
  • react 能够用服务器渲染
  • react 遵循单向数据流 或者数据绑定

React 中的 key 是什么?为什么它们很重要?

key 能够帮忙 React 跟踪循环创立列表中的虚构 DOM 元素,理解哪些元素已更改、增加或删除。
每个绑定 key 的虚构 DOM 元素,在兄弟元素之间都是举世无双的。在 React 的和解过程中,比拟新的虛拟 DOM 树与上一个虛拟 DOM 树之间的差别,并映射到页面中。key 使 React 解决列表中虛拟 DOM 时更加高效,因为 React 能够应用虛拟 DOM 上的 key 属性,疾速理解元素是新的、须要删除的,还是批改过的。如果没有 key,Rεat 就不晓得列表中虚构 DOM 元素与页面中的哪个元素绝对应。所以在创立列表的时候,不要疏忽 key。

为什么 React 要用 JSX?

JSX 是一个 JavaScript 的语法扩大,或者说是一个相似于 XML 的 ECMAScript 语法扩大。它自身没有太多的语法定义,也不冀望引入更多的规范。

其实 React 自身并不强制应用 JSX。在没有 JSX 的时候,React 实现一个组件依赖于应用 React.createElement 函数。代码如下:

class Hello extends React.Component {render() {
    return React.createElement(
        'div',
        null, 
        `Hello ${this.props.toWhat}`
      );
  }
}
ReactDOM.render(React.createElement(Hello, {toWhat: 'World'}, null),
  document.getElementById('root')
);

而 JSX 更像是一种语法糖,通过相似 XML 的形容形式,刻画函数对象。在采纳 JSX 之后,这段代码会这样写:

class Hello extends React.Component {render() {return <div>Hello {this.props.toWhat}</div>;
  }
}
ReactDOM.render(
  <Hello toWhat="World" />,
  document.getElementById('root')
);

通过比照,能够清晰地发现,代码变得更为简洁,而且代码构造档次更为清晰。

因为 React 须要将组件转化为虚构 DOM 树,所以在编写代码时,实际上是在手写一棵构造树。而XML 在树结构的形容上天生具备可读性强的劣势。

但这样可读性强的代码仅仅是给写程序的同学看的,实际上在运行的时候,会应用 Babel 插件将 JSX 语法的代码还原为 React.createElement 的代码。

总结: JSX 是一个 JavaScript 的语法扩大,构造相似 XML。JSX 次要用于申明 React 元素,但 React 中并不强制应用 JSX。即便应用了 JSX,也会在构建过程中,通过 Babel 插件编译为 React.createElement。所以 JSX 更像是 React.createElement 的一种语法糖。

React 团队并不想引入 JavaScript 自身以外的开发体系。而是心愿通过正当的关注点拆散放弃组件开发的纯正性。

React-Router 如何获取 URL 的参数和历史对象?

(1)获取 URL 的参数

  • get 传值

路由配置还是一般的配置,如:'admin',传参形式如:'admin?id='1111''。通过 this.props.location.search 获取 url 获取到一个字符串'?id='1111' 能够用 url,qs,querystring,浏览器提供的 api URLSearchParams 对象或者本人封装的办法去解析出 id 的值。

  • 动静路由传值

路由须要配置成动静路由:如 path='/admin/:id',传参形式,如'admin/111'。通过this.props.match.params.id 获得 url 中的动静路由 id 局部的值,除此之外还能够通过useParams(Hooks) 来获取

  • 通过 query 或 state 传值

传参形式如:在 Link 组件的 to 属性中能够传递对象 {pathname:'/admin',query:'111',state:'111'};。通过this.props.location.statethis.props.location.query来获取即可,传递的参数能够是对象、数组等,然而存在毛病就是只有刷新页面,参数就会失落。

(2)获取历史对象

  • 如果 React >= 16.8 时能够应用 React Router 中提供的 Hooks
import {useHistory} from "react-router-dom";
let history = useHistory();

2. 应用 this.props.history 获取历史对象

let history = this.props.history;

ref 是一个函数又有什么益处?

  • 不便 react 销毁组件、从新渲染的时候去清空 refs 的货色,避免内存泄露

如何配置 React-Router 实现路由切换

(1)应用<Route> 组件

路由匹配是通过比拟 <Route> 的 path 属性和以后地址的 pathname 来实现的。当一个 <Route> 匹配胜利时,它将渲染其内容,当它不匹配时就会渲染 null。没有门路的 <Route> 将始终被匹配。

// when location = {pathname: '/about'}
<Route path='/about' component={About}/> // renders <About/>
<Route path='/contact' component={Contact}/> // renders null
<Route component={Always}/> // renders <Always/>

(2)联合应用 <Switch> 组件和 <Route> 组件

<Switch> 用于将 <Route> 分组。

<Switch>
    <Route exact path="/" component={Home} />
    <Route path="/about" component={About} />
    <Route path="/contact" component={Contact} />
</Switch>

<Switch> 不是分组 <Route> 所必须的,但他通常很有用。一个 <Switch> 会遍历其所有的子 <Route>元素,并仅渲染与以后地址匹配的第一个元素。

(3)应用 <Link>、<NavLink>、<Redirect> 组件

<Link> 组件来在你的应用程序中创立链接。无论你在何处渲染一个<Link>,都会在应用程序的 HTML 中渲染锚(<a>)。

<Link to="/">Home</Link>   
// <a href='/'>Home</a>

是一种非凡类型的 当它的 to 属性与以后地址匹配时,能够将其定义为 ” 沉闷的 ”。

// location = {pathname: '/react'}
<NavLink to="/react" activeClassName="hurray">
    React
</NavLink>
// <a href='/react' className='hurray'>React</a>

当咱们想强制导航时,能够渲染一个 <Redirect>,当一个<Redirect> 渲染时,它将应用它的 to 属性进行定向。

在哪个生命周期中你会收回 Ajax 申请?为什么?

Ajax 申请应该写在组件创立期的第五个阶段,即 componentDidMount 生命周期办法中。起因如下。
在创立期的其余阶段,组件尚未渲染实现。而在存在期的 5 个阶段,又不能确保生命周期办法肯定会执行(如通过 shouldComponentUpdate 办法优化更新等)。在销毀期,组件行将被销毁,申请数据变得无意义。因而在这些阶段发岀 Ajax 申请显然不是最好的抉择。
在组件尚未挂载之前,Ajax 申请将无奈执行结束,如果此时发出请求,将意味着在组件挂载之前更新状态(如执行 setState),这通常是不起作用的。
在 componentDidMount 办法中,执行 Ajax 即可保障组件曾经挂载,并且可能失常更新组件。

参考:前端 react 面试题具体解答

react 和 vue 的区别

相同点:

  1. 数据驱动页面,提供响应式的试图组件
  2. 都有 virtual DOM, 组件化的开发,通过 props 参数进行父子之间组件传递数据,都实现了 webComponents 标准
  3. 数据流动单向,都反对服务器的渲染 SSR
  4. 都有反对 native 的办法,react 有 React native,vue 有 wexx

不同点:

  1. 数据绑定:Vue 实现了双向的数据绑定,react 数据流动是单向的
  2. 数据渲染:大规模的数据渲染,react 更快
  3. 应用场景:React 配合 Redux 架构适宜大规模多人合作简单我的项目,Vue 适宜小快的我的项目
  4. 开发格调:react 举荐做法 jsx + inline style 把 html 和 css 都写在 js 了

vue 是采纳 webpack +vue-loader 单文件组件格局,html, js, css 同一个文件

如何通知 React 它应该编译生产环境版

通常状况下咱们会应用 WebpackDefinePlugin 办法来将 NODE_ENV 变量值设置为 production。编译版本中 React会疏忽 propType 验证以及其余的告警信息,同时还会升高代码库的大小,React 应用了 Uglify 插件来移除生产环境下不必要的正文等信息

在 Reducer 文件里,对于返回的后果,要留神哪些问题?

在 Reducer 文件里,对于返回的后果,必须要应用 Object.assign ()来复制一份新的 state,否则页面不会跟着数据刷新。

return Object.assign({}, state, {
  type: action.type,
  shouldNotPaint: true,
});

React-Router 4 的 Switch 有什么用?

Switch 通常被用来包裹 Route,用于渲染与门路匹配的第一个子 <Route><Redirect>,它外面不能放其余元素。

如果不加 <Switch>

import {Route} from 'react-router-dom'

<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>

Route 组件的 path 属性用于匹配门路,因为须要匹配 /Home,匹配 /loginLogin,所以须要两个 Route,然而不能这么写。这样写的话,当 URL 的 path 为“/login”时,<Route path="/" /><Route path="/login" /> 都会被匹配,因而页面会展现 Home 和 Login 两个组件。这时就须要借助 <Switch> 来做到只显示一个匹配组件:

import {Switch, Route} from 'react-router-dom'

<Switch>
    <Route path="/" component={Home}></Route>
    <Route path="/login" component={Login}></Route>
</Switch>

此时,再拜访“/login”门路时,却只显示了 Home 组件。这是就用到了 exact 属性,它的作用就是准确匹配门路,常常与<Switch> 联结应用。只有当 URL 和该 <Route> 的 path 属性完全一致的状况下能力匹配上:

import {Switch, Route} from 'react-router-dom'

<Switch>
   <Route exact path="/" component={Home}></Route>
   <Route exact path="/login" component={Login}></Route>
</Switch>

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

咱们该当将 AJAX 申请放到 componentDidMount 函数中执行,次要起因有下

  • React 下一代和谐算法 Fiber 会通过开始或进行渲染的形式优化利用性能,其会影响到 componentWillMount 的触发次数。对于 componentWillMount 这个生命周期函数的调用次数会变得不确定,React 可能会屡次频繁调用 componentWillMount。如果咱们将 AJAX 申请放到 componentWillMount 函数中,那么不言而喻其会被触发屡次,天然也就不是好的抉择。
  • 如果咱们将 AJAX 申请搁置在生命周期的其余函数中,咱们并不能保障申请仅在组件挂载结束后才会要求响应。如果咱们的数据申请在组件挂载之前就实现,并且调用了setState 函数将数据增加到组件状态中,对于未挂载的组件则会报错。而在 componentDidMount 函数中进行 AJAX 申请则能无效防止这个问题

何为 JSX

JSX 是 JavaScript 语法的一种语法扩大,并领有 JavaScript 的全副性能。JSX 生产 React “ 元素 ”,你能够将任何的 JavaScript 表达式封装在花括号里,而后将其嵌入到 JSX 中。在编译实现之后,JSX 表达式就变成了惯例的 JavaScript 对象,这意味着你能够在 if 语句和 for 循环外部应用 JSX,将它赋值给变量,承受它作为参数,并从函数中返回它。

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

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

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

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

非嵌套关系组件的通信形式?

即没有任何蕴含关系的组件,包含兄弟组件以及不在同一个父级中的非兄弟组件。

  • 能够应用自定义事件通信(公布订阅模式)
  • 能够通过 redux 等进行全局状态治理
  • 如果是兄弟组件通信,能够找到这两个兄弟节点独特的父节点, 联合父子间通信形式进行通信。

形容事件在 React 中的解决形式。

为了解决跨浏览器兼容性问题,React 中的事件处理程序将传递 SyntheticEvent 的实例,它是跨浏览器事件的包装器。这些 SyntheticEvent 与你习惯的原生事件具备雷同的接口,它们在所有浏览器中都兼容。
React 实际上并没有将事件附加到子节点自身。而是通过事件委托模式,应用单个事件监听器监听顶层的所有事件。这对于性能是有益处的。这也意味着在更新 DOM 时,React 不须要放心跟踪事件监听器。

Redux 实现原理解析

为什么要用 redux

React 中,数据在组件中是单向流动的,数据从一个方向父组件流向子组件(通过 props), 所以,两个非父子组件之间通信就绝对麻烦,redux 的呈现就是为了解决 state 外面的数据问题

Redux 设计理念

Redux是将整个利用状态存储到一个中央上称为 store, 外面保留着一个状态树store tree, 组件能够派发(dispatch) 行为 (action) 给store, 而不是间接告诉其余组件,组件外部通过订阅 store 中的状态 state 来刷新本人的视图

Redux 三大准则

  • 惟一数据源

整个利用的 state 都被存储到一个状态树外面,并且这个状态树,只存在于惟一的 store 中

  • 放弃只读状态

state是只读的,惟一扭转 state 的办法就是触发 actionaction 是一个用于形容以产生工夫的一般对象

  • 数据扭转只能通过纯函数来执行

应用纯函数来执行批改,为了形容 action 如何扭转 state 的,你须要编写reducers

Redux 源码

let createStore = (reducer) => {
    let state;
    // 获取状态对象
    // 寄存所有的监听函数
    let listeners = [];
    let getState = () => state;
    // 提供一个办法供内部调用派发 action
    let dispath = (action) => {
        // 调用管理员 reducer 失去新的 state
        state = reducer(state, action);
        // 执行所有的监听函数
        listeners.forEach((l) => l())
    }
    // 订阅状态变动事件,当状态扭转产生之后执行监听函数
    let subscribe = (listener) => {listeners.push(listener);
    }
    dispath();
    return {
        getState,
        dispath,
        subscribe
    }
}
let combineReducers=(renducers)=>{
    // 传入一个 renducers 治理组,返回的是一个 renducer
    return function(state={},action={}){let newState={};
        for(var attr in renducers){newState[attr]=renducers[attr](state[attr],action)

        }
        return newState;
    }
}
export {createStore,combineReducers};

正文完
 0