专栏名称: 前端之巅
InfoQ大前端技术社群:囊括前端、移动、Node全栈一线技术,紧跟业界发展步伐。
目录
相关文章推荐
康石石  ·  香港艺术留学集体抬门槛…… ·  2 天前  
康石石  ·  你的工业交互设计保研指南! ·  2 天前  
西安晚报  ·  哀悼!著名豫剧表演艺术家关灵凤逝世 ·  3 天前  
51好读  ›  专栏  ›  前端之巅

前端面试通关宝典:解析44道React测试题(上)

前端之巅  · 公众号  ·  · 2023-11-20 15:00

正文


作者|Yan Levin
译者|核子可乐
策划|丁晓昀

在面试 React 前端开发岗位时,我们当然应该为即将面对的技术问题做好充分准备。React 是目前用户界面构建领域最具人气的 JavaScript 库之一,企业雇主往往非常注重评估受试者对 React 核心概念、最佳实践以及相关技术方法的掌握情况。在本文中,我们将演讲 React 前端开发者在面试中经常遇到的 44 个问题。通过熟悉这些问题和答案,大家有望增加成功几率,充分展现自己在 React 开发方面的知识储备和技能水平。咱们闲言少叙,马上进入正题。

上篇是前22道题,下篇是后22道题,你能顺利通关吗?

1. 你了解哪些 React hooks?
  • useState: 用于管理函数组件中的状态。

  • useEffect: 用于在函数组件中执行 side effects,例如获取数据或订阅事件。

  • useContext: 用于访问函数组件当中 React 上下文的值。

  • useRef: 用于为跨渲染持续存在的元素或值创建可变引用。

  • useCallback: 用于记忆函数,以防止不必要的重新渲染。

  • useMemo: 用于记忆值,即将成本高昂的计算结果缓存起来以提高性能。

  • useReducer: 负责使用 reducer 函数管理状态,原理类似于 Redux。

  • useLayoutEffect: 与 useEffect 类似,但效果会在所有 DOM 更改之后再同步运行。

这些 hooks 提供强大的工具,可用于管理状态、处理 side effects 和重用 React 函数组件当中的逻辑。

了解更多:https://react.dev/reference/react

2. 虚拟 DOM 是什么?

虚拟 DOM 是 React 中提出的概念,用于为实际 DOM(文档对象模型)创建一个轻量化虚拟表示,并将其存储在内存当中。这是一种用于优化 Web 应用程序性能的编程技术。

当 React 组件的数据或状态发生变更时,虚拟 DOM 也会随之更新,而非直接操作实际 DOM。此后,虚拟 DOM 计算组件先前状态与更新状态之间差异的过程,被称为“diffing”。

一旦发现存在差异,React 将仅更新实际 DOM 当中的必要部分,借此高效反映变更内容。这种方式最大限度减少了实际 DOM 上的操作数量,进而提高了应用程序的整体性能。

通过使用虚拟 DOM,React 在提供动态及交互式用户界面创建方法的同时,也保证应用程序始终拥有最佳效率和渲染速度。

3. 如何渲染一个元素数组?

要渲染一个元素数组,可以使用 map() 方法迭代该数组,并返回一个新的 React 元素数组。

const languages = [  "JavaScript",  "TypeScript",  "Python",];
function App() { return (
    {languages.map((language) =>
  • {language}
  • )}
);}

了解更多:https://react.dev/learn/rendering-lists

4. 受控组件与非受控组件之间有何区别?

受控组件与非受控组件之间的最大区别,在于如何管理和更新自身状态。

受控组件的状态由 React 负责控制,该组件接受其当前值并通过 props 进行更新。当值发生改变时,它会触发回调函数,也就是说该组件不会存储自己的内部状态。相反,由父组件管理该值并将其传递给受控组件。

import { useState } from 'react'; 
function App() { const [value, setValue] = useState('');
return (

Controlled Component

setValue(e.target.value)} />
);

另一方面,非受控组件则使用 refs 或其他方法在内部管理自身状态。这类组件独立存储并更新其状态,不依赖于 props 或回调。父组件对非受控组件的状态控制能力较弱。

import { useRef } from 'react'; 
function App() { const inputRef = useRef(null);
return (

Uncontrolled Component

);

了解更多:https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components

5. 基于类的 React 组件,
与函数式 React 组件之间有何区别?

基于类的组件和函数组件之间的主要区别,在于二者的定义方式和所用语法不同。

基于类的组件被定义为 ES6 类,属于 React.Component 类的扩展。它们使用 render 方法返回定义组件输出的 JSX(JavaScript XML)。类组件可以通过 this.state 和 this.setState() 访问其生命周期方法和状态管理。

class App extends React.Component {  state = {    value: 0,  };
handleAgeChange = () => { this.setState({ value: this.state.value + 1 }); };
render() { return ( <>

Value is {this.state.value}

Increment value > ); }}

另一方面,函数组件被定义为简单的 JavaScript 函数。它们接受 props 作为参数并直接返回 JSX。函数组件无权访问生命周期方法或者状态。但随着 React 16.8 中 React hooks 机制的出现,函数组件现在也可以管理状态并使用其他功能,例如上下文和效果。

import { useState } from 'react';
const App = () => { const [value, setValue] = useState(0);
const handleAgeChange = () => { setValue(value + 1); };
return ( <>

Value is {value}

Increment value > );}

一般来讲,函数组件往往更简单、易于阅读和测试。所以除非确实需要类组件,否则建议大家尽量使用函数组件。

6. 组件的生命周期方法有哪些?

生命周期方法,属于一种钩入组件生命周期各个阶段的方法,允许开发者在特定时间执行特定的代码。

以下是几种主要生命周期方法:

  1. constructor: 这也是创建组件时调用的第一个方法,用于初始化状态并绑定事件处理程序。在函数组件中,我们可以使用 useState hook 来实现类似的效果。

  2. render: 此方法负责渲染 JSX 标记,并返回要在屏幕上显示的内容。

  3. componentDidMount: 此方法将在组件于 DOM 中渲染后被立即调用,通常用于初始化任务,例如 API 调用或设置事件侦听器。

  4. componentDidUpdate: 此方法会在组件的 props 或 state 发生变更时被调用,允许开发者执行 side effects、根据变更更新组件或者触发其他 API 调用。

  5. componentWillUnmount: 此方法会在组件从 DOM 中删除之前被调用,用于清理conponentDidMount 中设置的一切资源,例如删除事件侦听器或取消计时器。

某些生命周期方法(例如 componentWillMount、componentWillReceiveProps 和 componentWillUpdate)现已被弃用,或者被其他方法或 hooks 所替代。

至于“this”方法,是指类组件的当前实例。我们可以用它访问组件内的属性和方法。在函数组件中不需要使用“this”,因为函数不会绑定至特定实例。

7. 使用 useState 时应该注意什么?

useState 会返回一个状态值和一条更新该值的函数。

const [value, setValue] = useState('Some state');

在初始渲染期间,返回的状态与传递来的首个参数值相匹配。setState 函数用于更新该状态,它采用新的状态值作为参数并对组件的重新渲染操作进行排队。setState 函数还可以接受回调函数作为参数,该函数会将之前的状态值作为参数。

了解更多:https://react.dev/reference/react/useState

8. 使用 useEffect 时应该注意什么?

useEffect hook 允许我们在函数组件中执行 side effects。

在 React 的渲染阶段,函数组件的主体之内不得出现突变、订阅、计时器、日志记录及其他 side effects,这些可能导致用户界面中出现难以理解的错误和一致性冲突。

相反,这里建议使用 useEffect。传递给 useEffect 的函数将在渲染被提交至屏幕后才开始执行;而如果您传递一组依赖项作为第二参数,则每当有依赖项发生变更时,都会调用该函数。

useEffect(() => {  console.log('Logging something');}, [])

了解更多:https://react.dev/reference/react/useEffect

9. 如何跟踪函数组件是否被卸载?

一般来说,useEffect 所创建的资源需要在组件离开屏幕前进行清理或重置,例如订阅或计时器标记。

为此,传递给 useEffect 的函数可以返回一个清理函数。该清理函数将在组件被从用户界面中删除之前运行,防止发生内存泄漏。此外,如果组件经过多次渲染(属于常见情况),则在执行下一效果之前会先清除上一效果。

useEffect(() => {  function handleChange(value) {    setValue(value);  }  SomeAPI.doFunction(id, handleChange);
return function cleanup() { SomeAPI.undoFunction(id, handleChange); };})
10. React 中的 props 是什么?

Props 是指从父组件传递给当前组件的数据。Props 有只读限制,无法更改。

// 父组件const Parent = () => {  const data = "Hello, World!";
return (
);};
// 子组件const Child = ({ data }) => { return
{data}
;
};

了解更多:https://react.dev/learn/passing-props-to-a-component

11. 什么是状态管理器?你曾经使用过
哪些状态管理器,或者了解过哪些状态管理器?

状态管理器是帮助管理应用程序状态的工具或库,负责提供一个集中的存储或容器,用以容纳并管理可由应用程序中各个组件访问并更新的数据。

状态管理器可以解决以下几个问题。首先,最好将数据同与之相关的逻辑 / 组件彼此分离。第二,在使用本地状态并在组件之间进行传递时,由于组件中可能存在深层嵌套,因此代码往往会比较复杂。通过建立全局存储,我们可以访问并修改来自任意组件的数据。

除了 React Context 以外,常见的状态管理库还有 Redux 和 MobX。

了解更多:https://mobx.js.org/README.html

了解更多:https://redux-toolkit.js.org/

12. 在哪些情况下可以使用本地状态,
什么时候应该使用全局状态?

如果仅需要在单一组件内使用,而且无需传递给其他组件,则建议使用本地状态。本地状态还适用于组件只需在列表中表示单一项目的情况。但如果组件拆分涉及到嵌套组件,而且数据需要沿层次结构进行传递,则最好使用全局状态。

13. Redux 中的 reducer 是什么,
它会用到哪些参数?

Reducer 属于纯函数,并将状态和操作作为参数。在 reducer 内部,我们会跟踪接收到的 action 类型,再根据它修改状态并返回一个新的状态对象。

export default function appReducer(state = initialState, action) {  // Reducer通常会查看action类型字段来决定如何执行  switch (action.type) {    // 根据action的具体类型选择执行方式    default:      // 如果此reducer无法识别action类型      // 或者此action不重要,则直接返回现有状态  }}

了解更多:https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers

14. Action 是什么,
我们如何改变 Redux 中的状态?

Action 属于简单的 JavaScript 对象,其组成为字段加类型。

{  type: "SOME_TYPE"}

我们也可以为其添加数据作为负载payload。要改变状态,则须调用我们传递给action的dispatch调度函数。

{  type: "SOME_TYPE",  payload: "Any payload",}

了解更多:https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers

15. Redux 实现的是哪种模式?

Redux 实现的是 Flux 模式,即应用程序的可预测状态管理模式。它通过引入单向数据流与应用程序状态的集中存储机制,帮助管理应用程序状态。

了解更多:https://www.newline.co/fullstack-react/30-days-of-react/day-18/#:~:text=Flux%20is%20a%20pattern%20for,default%20method%20for%20handling%20data.

16. Mobx 实现的是哪种模式?

Mobx 实现的是 Observer 模式,也被称为发布 - 订阅模式。

了解更多:https://www.patterns.dev/posts/observer-pattern

17. 在使用 Mobx 时应该注意什么?

Mobx 提供 observable 和 computed 等修饰器来定义可观察状态与反应函数。用 action 修饰的操作用于修改状态,确保跟踪所有变更。Mobx 还提供自动依赖项跟踪、不同反应类型、对反应性的细粒度控制,以及通过 mobx-react 包与 React 的无缝集成。总的来说,Mobx 能够以可观察状态的变化为基础,自动执行更新过程以简化状态管理。

18. 如何访问 Mobx 状态下的变量?

我们可以使用 observalbe 装饰器将该变量定义为 observable,借此实现对状态下变量的访问。例如:

import { observable, computed } from 'mobx';
class MyStore { @observable myVariable = 'Hello Mobx';
@computed get capitalizedVariable() { return this.myVariable.toUpperCase(); }}
const store = new MyStore();console.log(store.capitalizedVariable); // Output: HELLO MOBX
store.myVariable = 'Hi Mobx';console.log(store.capitalizedVariable); // Output: HI MOBX

在本示例中,使用 observable 装饰器将 myVariable 定义为 observable。之后,我们可以使用 store.myVariable 访问该变量。如此一来,对 myVariable 所做的任何更改都会自动触发相关组件或反应的更新。







请到「今天看啥」查看全文