必须要会的 50 个 React 面试题

    |     2020年9月12日   |   reactjs, web前端技术   |     0 条评论   |    887

如果你是有抱负的前端,正在准备面试,可以把这 50 题当 React 复习提纲。JavaScript 工具在市场里站稳后,React 需求涨得很快;它虽只覆盖 MVC 的 View,却常拿来和 Angular、Meteor、Vue 比较。

截至原文写作时 GitHub 约有 1000 名贡献者。Virtual DOM 和可复用组件最吸引人。下面按基本知识、组件、Redux、路由分类,问与答全部保留。

╬в╨┼╜╪═╝_20200916114527

JS 框架的趋势

一、基本知识

1. 区分 Real DOM 和 Virtual DOM

Real DOM Virtual DOM
更新缓慢 更新更快
可以直接更新 HTML 无法直接更新 HTML
元素更新则创建新 DOM 元素更新则更新 JSX
DOM 操作代价高 DOM 操作更简单
更耗内存 内存消耗更少

2. 什么是 React?

  • Facebook 2011 年做的前端 JavaScript 库
  • 基于组件,便于搭可复用 UI
  • 适合复杂、交互强的 Web 和移动 UI
  • 2015 年开源,社区很大

3. 有什么特点?

  1. 用虚拟 DOM而不是真实 DOM
  2. 可以服务端渲染
  3. 遵循单向数据流或数据绑定

4. 主要优点

  1. 提升性能
  2. 客户端、服务器端都能用
  3. JSX 让代码更好读
  4. 容易和 Meteor、Angular 等集成
  5. UI 测试更好写

5. 限制

  1. 只是库,不是完整框架
  2. 体积大,需要时间吃透
  3. 新手可能觉得难
  4. 内联模板和 JSX 让编码显得复杂

6. 什么是 JSX?

JSX 是 JavaScript XML 的简写。React 用它把 JS 表现力和类 HTML 模板写在一起,文件更好懂,也有助于可靠性和性能。例如:

render(){
    return(        
        <div>
            <h1> Hello World from Edureka!!</h1>
        </div>
    );
}

7. Virtual DOM 怎么工作?

Virtual DOM 是轻量 JS 对象,一开始是 real DOM 的副本:节点树,元素、属性和内容都是对象。render 从组件建树,再按数据模型变化(用户或系统)更新这棵树。三步:

  1. 底层数据一变,整份 UI 在 Virtual DOM 里重描述。Virtual DOM 1
  2. 算新旧表示的差异。Virtual DOM 2
  3. 只把真正变的补到 real DOM。Virtual DOM 3

8. 为什么浏览器读不了 JSX?

浏览器只吃 JavaScript 对象。JSX 要先经 Babel 等转成 JS 对象再交给浏览器。

9. 和 ES5 比,ES6 写法有何不同?

require 与 import:

// ES5
var React = require('react');
 
// ES6
import React from 'react';

export 与 exports:

// ES5
module.exports = Component;
 
// ES6
export default Component;

component 和 function:

// ES5
var MyComponent = React.createClass({
    render: function() {
        return
			<h3>Hello Edureka!</h3>;
    }
});
 
// ES6
class MyComponent extends React.Component {
    render() {
        return
			<h3>Hello Edureka!</h3>;
    }
}

props:

// ES5
var App = React.createClass({
    propTypes: { name: React.PropTypes.string },
    render: function() {
        return
			<h3>Hello, {this.props.name}!</h3>;
    }
});

// ES6
class App extends React.Component {
    render() {
        return
			<h3>Hello, {this.props.name}!</h3>;
    }
}

state:

// ES5
var App = React.createClass({
    getInitialState: function() {
        return { name: 'world' };
    },
    render: function() {
        return
	        <h3>Hello, {this.state.name}!</h3>;
    }
});

// ES6
class App extends React.Component {
    constructor() {
        super();
        this.state = { name: 'world' };
    }
    render() {
        return
	        <h3>Hello, {this.state.name}!</h3>;
    }
}

10. React 和 Angular 有何不同?

主题 React Angular
体系结构 只有 MVC 中的 View 完整 MVC
渲染 可以服务端渲染 客户端渲染
DOM virtual DOM real DOM
数据绑定 单向 双向
调试 编译时 运行时
作者 Facebook Google

二、React 组件

11. 「在 React 中,一切都是组件」

组件是 UI 积木,把界面拆成独立可复用的小块,彼此不影响其余 UI。

12. render() 的目的

每个组件都要有 render(),返回 React 元素(对原生 DOM 的描述)。多个 HTML 元素必须包在一个封闭标签里。函数必须纯:同样输入得到同样输出。

13. 如何把两个或多个组件嵌进一个?

class MyComponent extends React.Component{
    render(){
        return(          
			<div>
            	<h1>Hello</h1>
                <Header/>
            </div>
        );
    }
}
class Header extends React.Component{
    render(){
        return
			<h1>Header Component</h1>   
   };
}
ReactDOM.render(
    <MyComponent/>, document.getElementById('content')
);

14. 什么是 Props?

Props 是 properties 的简写,只读、必须保持纯(不可变)。总是父传子,子不能把 prop 回传给父,从而维持单向数据流,常用来渲染动态数据。

15. 状态是什么?怎么用?

state 是组件的数据来源,应尽量简单。它决定呈现和行为,可变,用来做动态交互。通过 this.state 读取(不是函数调用)。

16. state 和 props

条件 State Props
从父组件接收初始值 Yes Yes
父组件可以改变值 No Yes
在组件中设置默认值 Yes Yes
在组件内部变化 Yes No
设置子组件的初始值 Yes Yes
在子组件内部更改 No Yes

17. 如何更新状态?

用 this.setState():

class MyComponent extends React.Component {
    constructor() {
        super();
        this.state = {
            name: 'Maxx',
            id: '101'
        }
    }
    render()
        {
            setTimeout(()=>{this.setState({name:'Jaeha', id:'222'})},2000)
            return (              
				<div>
                	<h1>Hello {this.state.name}</h1>
					<h2>Your Id is {this.state.id}</h2>
                </div>
            );
        }
    }
ReactDOM.render(
    <MyComponent/>, document.getElementById('content')
);

18. 箭头函数

箭头函数(=>)是函数表达式的短写法,能绑住组件上下文(ES6 默认不自动绑定)。高阶函数里很好用。

//General way
render() {    
    return(
        <MyInput onChange = {this.handleChange.bind(this) } />
    );
}
//With Arrow Function
render() {  
    return(
        <MyInput onChange = { (e)=>this.handleOnChange(e) } />
    );
}

19. 有状态 vs 无状态

有状态组件 无状态组件
内存中保存状态变化信息 计算内部状态(通常无自身 state)
有权改变状态 无权改变状态
包含过去、现在、未来可能的状态 不包含这些变化情况
接收无状态组件的更新请求,再把 props 传下去 从有状态组件收 props,当作回调来用

20. 生命周期阶段

  1. 初始渲染:组件开始生命并进入 DOM
  2. 更新:已在 DOM 中,仅当 prop 或 state 变才可能再渲染
  3. 卸载:销毁并从 DOM 删除

21. 生命周期方法

  1. componentWillMount():渲染前,客户端和服务器都会执行
  2. componentDidMount():仅第一次渲染后在客户端执行
  3. componentWillReceiveProps():从父组件收到 props,下一次渲染前
  4. shouldComponentUpdate():按条件返回 true/false 决定要不要更新;默认返回 true
  5. componentWillUpdate():写入 DOM 前
  6. componentDidUpdate():渲染后立刻
  7. componentWillUnmount():卸载后,用于清理

22. 事件是什么?

对悬停、点击、按键等的响应。类似 DOM 事件,但:

  1. 用驼峰命名,不是全小写
  2. 处理函数作为函数传递,不是字符串

事件参数带一组特定属性,只能在对应处理函数里访问。

23. 如何创建事件?

class Display extends React.Component({    
    show(evt) {
        // code   
    },   
    render() {      
        // Render the div with an onClick prop (value is a function)        
        return (            
            <div onClick={this.show}>Click Me!</div>
        );    
    }
});

24. 合成事件

合成事件是包在浏览器原生事件外的跨浏览器包装,把不同浏览器行为收成一套 API,属性表现一致。

25. refs

Refs 是引用。用来存对某个 React 元素或组件的引用(render 返回的那个)。量 DOM 或给组件加命令式方法时用得上。

class ReferenceDemo extends React.Component{
     display() {
         const name = this.inputDemo.value;
         document.getElementById('disp').innerHTML = name;
     }
render() {
    return(        
          <div>
            Name: <input type="text" ref={input => this.inputDemo = input} />
            <button name="Click" onClick={this.display}>Click</button>            
            <h2>Hello <span id="disp"></span> !!!</h2>
          </div>
    );
   }
 }

26. 什么时候用 Refs

  • 管理焦点、选中文本或媒体播放
  • 触发式动画
  • 集成第三方 DOM 库

27. 如何模块化代码?

用 export / import 把组件写在不同文件:

//ChildComponent.jsx
export default class ChildComponent extends React.Component {
    render() {
        return(           
              <div>
              	<h1>This is a child component</h1>
              </div>
        );
    }
}
 
//ParentComponent.jsx
import ChildComponent from './childcomponent.js';
class ParentComponent extends React.Component {    
    render() {        
        return(           
             <div>               
                <App />          
             </div>       
        );  
    }
}

28. 如何创建表单

形态像 HTML,但值在 state 里,只能 setState() 更新。提交由 JS 函数处理,函数能读到用户输入。

handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
}
 
render() {
    return (        
        <form onSubmit={this.handleSubmit}>
            <label>
                Name:
                <input type="text" value={this.state.value} onChange={this.handleSubmit} />
            </label>
            <input type="submit" value="Submit" />
        </form>
    );
}

29. 受控 vs 非受控

受控组件 非受控组件
不自己维持状态 自己维持状态
数据由父组件控制 数据由 DOM 控制
通过 props 拿当前值,回调通知更改 用 Refs 拿当前值

30. 什么是 HOC?

高阶组件是复用组件逻辑的模式:一个组件里包另一个组件,接收子组件的动态能力,但不改、不复制输入组件的行为。可以看成「纯」组件。

31. HOC 能做什么?

  • 代码复用,逻辑和引导抽象
  • 渲染劫持
  • 状态抽象和控制
  • Props 控制

32. 纯组件

纯(Pure)组件是最简单、最快的一种,可替换只有 render() 的组件,让代码更简单、性能更好。

33. key 为什么重要?

key 用来识别 Virtual DOM 元素和对应数据。React 靠它复用 DOM、只重排不整树重渲染,必须是唯一的数字或字符串,有利于性能。

三、React Redux

34. MVC 的主要问题

  • DOM 操作代价高
  • 运行慢、效率低
  • 浪费内存
  • 循环依赖迫使组件模型围着 models 和 views 转

35. 解释 Flux

╬в╨┼╜╪═╝_20200916114746

Flux 强制单向数据流。派生数据由拥有全部数据权限的中心 store 管,组件之间经它通信。应用里的数据更新只能发生在这里,更稳、运行时错误更少。

36. 什么是 Redux?

可预测的状态容器,管整个应用状态。用它写的应用更好测,跨环境行为一致。

37. 三个原则

  1. 单一事实来源:状态放在唯一 store 的对象树里,便于跟踪、调试
  2. 状态只读:只能 dispatch 一个描述变化的 action(普通对象)
  3. 用纯函数改状态:reducer 的返回值只取决于参数

╬в╨┼╜╪═╝_20200916115242

38. 「单一事实来源」

整个程序状态集中在 Store,组件都从这里收更新,变化可追踪。

39. Redux 的组件

  1. Action:描述发生了什么
  2. Reducer:决定状态怎么变
  3. Store:整棵状态树
  4. View:只展示 Store 给的数据

40. 数据如何流动?

╬в╨┼╜╪═╝_20200916115329

41. 如何定义 Action?

必须有 type,表示动作种类,一般是字符串常量,也可加其他字段。由 Action Creator 函数创建:

function addTodo(text) {
       return {
                type: ADD_TODO,    
                 text
    }
}

42. Reducer 的作用

纯函数:接收旧 state 和 action,返回新 state。按 action.type 决定更新;不需要处理就返回原 state。

43. Store 的意义

JS 对象,保存状态,并提供读状态、dispatch、注册监听的方法。整棵树只有这一份,所以简单可预测。可把中间件传进 store 做日志等。所有操作经 reducer 得到新状态。

44. Redux 和 Flux

Flux Redux
Store 包含状态和更改逻辑 Store 和更改逻辑分开
多个 Store 只有一个 Store
Store 互不影响、平级 带分层 reducer 的单一 Store
有单一调度器 没有调度器概念
React 组件订阅 store 容器组件是连接上的
状态可变 状态不可变

45. Redux 优点

  • 结果可预测:永远只有一个真实来源
  • 可维护:结构严、结果可预期
  • 服务端渲染:把服务器上的 store 传给客户端,利于首屏
  • 开发者工具:从 action 到 state 都能跟
  • 社区:生态大
  • 好测:多为小的纯函数
  • 组织:代码怎么放有约定,团队更一致

四、React 路由

46. 什么是 React 路由?

建在 React 上的路由库,给应用加屏幕和流程,让 URL 和页面数据同步。用来做单页应用,API 相对简单。

47. 为什么 v4 要用 Switch?

<Switch> 包多条 <Route> 时,只渲染第一条匹配的路由,后面的不再比。适合「多条里只显示一条」的场景。

48. 为什么需要路由?

用户访问某 URL 时,若和某条 Route 的 path 匹配就进对应视图。所以要引入路由库,每条路由一个独特视图:

<switch>
    <route exact path=’/’ component={Home}/>
    <route path=’/posts/:id’ component={Newpost}/>
    <route path=’/posts’   component={Post}/>
</switch>

49. React Router 的优点

  1. v4 的 API 也是组件化:根上是 Router,里面包 <Route> 子路由
  2. 不必手设 history:把路由包在 Router 组件里即可
  3. Web / Native / Core 分包,体积更小,风格接近,好切换

50. 和常规路由有何不同?

主题 常规路由 React 路由
参与的页面 每个视图一个新文件 只涉及单个 HTML 页面
URL 更改 HTTP 请求要新 HTML 只改 history
体验 真的在不同页面间切 用户感觉在切页,实际还是 SPA

希望这套题能帮你准备面试。

作者:前端先锋
链接:https://juejin.im/post/6844903806715559943

一句话总结:面试 React 先分清 Virtual DOM、props/state、生命周期和受控组件,再用 Redux 的单向数据流和 React Router 的 Switch 把应用串起来。

转载请注明来源:必须要会的 50 个 React 面试题
本文链接地址:https://ai.zhousir.top/?p=3030
回复 取消