面试 React 框架八股文十问十答第十一期

作者:程序员小白条个人博客

相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!

⭐点赞⭐收藏⭐不迷路!⭐

1)React 与 Vue 的 diff 算法有何不同?

React 和 Vue 在处理虚拟 DOM 的 diff 算法上有一些不同之处:

  • React: 使用深度优先搜索策略,通过同层比较和唯一 key 来尽早发现不同之处。React 的 diff 算法是基于组件实例,而且在更新时会销毁旧组件并创建新组件。
  • Vue: 使用双指针算法,采用一种更接近模板的结构。Vue 的 diff 算法是基于模板的指令,通过比较模板中的指令来更新 DOM。Vue 2.x 使用的是一种“先序深度优先”的策略。

虽然两者在实现细节上有差异,但目标都是尽量减少实际 DOM 操作,提高性能。

2)React组件命名推荐的方式是哪个?

在 React 中,组件命名的一般约定是采用帕斯卡命名法(PascalCase),即首字母大写,例如:

class MyComponent extends React.Component {
  // ...
}

这种命名方式有助于区分 React 组件与普通的 HTML 元素,也符合 React 社区的一致性约定。

3)react 最新版本解决了什么问题,增加了哪些东西

React 16.x的三大新特性 Time Slicing、Suspense、 hooks

  • Time Slicing(解决CPU速度问题)使得在执行任务的期间可以随时暂停,跑去干别的事情,这个特性使得react能在性能极其差的机器跑时,仍然保持有良好的性能
  • Suspense (解决网络IO问题) 和lazy配合,实现异步加载组件。 能暂停当前组件的渲染, 当完成某件事以后再继续渲染,解决从react出生到现在都存在的「异步副作用」的问题,而且解决得非的优雅,使用的是 T异步但是同步的写法,这是最好的解决异步问题的方式
  • 提供了一个内置函数componentDidCatch,当有错误发生时,可以友好地展示 fallback 组件; 可以捕捉到它的子元素(包括嵌套子元素)抛出的异常; 可以复用错误组件。

(1)React16.8 加入hooks,让React函数式组件更加灵活,hooks之前,React存在很多问题:

  • 在组件间复用状态逻辑很难
  • 复杂组件变得难以理解,高阶组件和函数组件的嵌套过深。
  • class组件的this指向问题
  • 难以记忆的生命周期

hooks很好的解决了上述问题,hooks提供了很多方法

  • useState 返回有状态值,以及更新这个状态值的函数
  • useEffect 接受包含命令式,可能有副作用代码的函数。
  • useContext 接受上下文对象(从 React.createContext返回的值)并返回当前上下文值,
  • useReducer useState 的替代方案。接受类型为 (state,action)=> newState的reducer,并返回与dispatch方法配对的当前状态。
  • useCalLback 返回一个回忆的memoized版本,该版本仅在其中一个输入发生更改时才会更改。纯函数的输入输出确定性 o useMemo 纯的一个记忆函数 o useRef 返回一个可变的ref对象,其Current 属性被初始化为传递的参数,返回的 ref 对象在组件的整个生命周期内保持不变。
  • useImperativeMethods 自定义使用ref时公开给父组件的实例值
  • useMutationEffect 更新兄弟组件之前,它在React执行其DOM改变的同一阶段同步触发
  • useLayoutEffect DOM改变后同步触发。使用它来从DOM读取布局并同步重新渲染

4)react 实现一个全局的 dialog

要在 React 中实现一个全局的 dialog,可以使用 React 的 Context API 或者状态管理库,例如 Redux。以下是一个简单的例子,使用 React Context API:

// DialogContext.js
import React, { createContext, useState, useContext } from 'react';

const DialogContext = createContext();

export const DialogProvider = ({ children }) => {
  const [isOpen, setIsOpen] = useState(false);
  const [content, setContent] = useState(null);

  const openDialog = (newContent) => {
    setContent(newContent);
    setIsOpen(true);
  };

  const closeDialog = () => {
    setContent(null);
    setIsOpen(false);
  };

  return (
    <DialogContext.Provider value={{ isOpen, openDialog, closeDialog }}>
      {children}
      {isOpen && content && <div className="dialog">{content}</div>}
    </DialogContext.Provider>
  );
};

export const useDialog = () => {
  return useContext(DialogContext);
};

在应用的顶层组件中,使用 DialogProvider 包裹整个应用:

// App.js
import React from 'react';
import { DialogProvider } from './DialogContext';
import MyComponent from './MyComponent';

const App = () => {
  return (
    <DialogProvider>
      <MyComponent />
    </DialogProvider>
  );
};

export default App;

在任何需要弹出 dialog 的组件中,可以使用 useDialog hook:

// MyComponent.js
import React from 'react';
import { useDialog } from './DialogContext';

const MyComponent = () => {
  const { openDialog } = useDialog();

  const handleClick = () => {
    openDialog(<p>This is a dialog content.</p>);
  };

  return (
    <div>
      <button onClick={handleClick}>Open Dialog</button>
    </div>
  );
};

export default MyComponent;

5)React 数据持久化有什么实践吗?

在 React 应用中,数据持久化通常涉及到将应用的状态保存到本地存储或者其他持久化存储中,以便在页面刷新或用户关闭应用后能够恢复之前的状态。以下是一些 React 数据持久化的实践方法:

  • 使用 Web Storage API: 使用 localStoragesessionStorage 可以将数据保存在浏览器的本地存储中。这对于小量数据而言是一个简单有效的方案。
// 保存数据到 localStorage
localStorage.setItem('key', JSON.stringify(data));

// 从 localStorage 恢复数据
const storedData = JSON.parse(localStorage.getItem('key'));
  • 使用 Cookies: 如果需要在客户端和服务器之间传递数据,可以使用 Cookies 进行数据持久化。
// 设置 Cookie
document.cookie = 'key=value; expires=Thu, 18 Dec 2022 12:00:00 UTC; path=/';

// 读取 Cookie
const storedValue = document.cookie.replace(/(?:(?:^|.*;\s*)key\s*=\s*([^;]*).*$)|^.*$/, '\$1');
  • 使用 IndexedDB: IndexedDB 是一个浏览器端的数据库,可以存储大量结构化数据。
  • 使用状态管理库: 如果应用使用状态管理库(如 Redux),可以结合中间件将状态保存到本地存储中,以便在刷新页面后恢复状态。

6)对 React 和 Vue 的理解,它们的异同

React 和 Vue 都是流行的前端框架,用于构建用户界面,但它们有一些显著的异同点:

相似之处:

  • 组件化: React 和 Vue 都采用了组件化的开发模式,允许开发者将应用拆分成可复用的组件。
  • 虚拟 DOM: 两者都使用虚拟 DOM 机制来提高性能,通过在内存中维护一个虚拟的 DOM 树来减少实际 DOM 操作。
  • 响应式: Vue 和 React 都支持响应式数据绑定,当数据变化时,视图会自动更新。

不同之处:

  • 语法: React 使用 JSX(JavaScript XML)语法,它是一种 JavaScript 的扩展,允许在 JavaScript 中编写类似 XML/HTML 的代码。而 Vue 使用模板语法,可以在 HTML 模板中直接插入表达式和指令。
  • 学习曲线: Vue 被认为是学习曲线较平缓的框架,适合初学者。React 的学习曲线可能相对陡峭,尤其是对于理解 JSX 和一些高级概念的开发者。
  • 状态管理: 在状态管理上,React 通常使用库如 Redux 进行全局状态管理,而 Vue 内置了 Vuex 来处理全局状态。

总体而言,React 更注重灵活性和可组合性,而 Vue 更注重开箱即用和简单性。选择使用哪个框架通常取决于团队的经验、项目的需求以及开发者个人的偏好。

7)可以使用TypeScript写React应用吗?怎么操作?

是的,可以使用 TypeScript 来编写 React 应用。React 官方提供了对 TypeScript 的原生支持,通过安装相应的包即可开始在项目中使用 TypeScript。

以下是一些基本步骤:

  1. 创建 React 项目: 使用 Create React App 工具来初始化一个 React 项目。

    npx create-react-app my-react-app --template typescript
    

    这会创建一个带有 TypeScript 配置的 React 项目。

  2. 安装 TypeScript 支持: 如果你的项目没有使用 Create React App,你需要手动安装 TypeScript 和相关的类型定义。

    npm install --save typescript @types/react @types/react-dom @types/node
    
  3. 将文件重命名为 .tsx 将 React 组件的文件后缀从 .js.jsx 改为 .tsx,以告诉 TypeScript 这是一个包含 JSX 的文件。

  4. 编写 TypeScript 代码:.tsx 文件中编写 React 组件,并使用 TypeScript 的类型系统来提高代码的健壮性。

    // ExampleComponent.tsx
    import React from 'react';
    
    interface Props {
      message: string;
    }
    
    const ExampleComponent: React.FC<Props> = ({ message }) => {
      return <div>{message}</div>;
    };
    
    export default ExampleComponent;
    

现在,你可以在 React 项目中使用 TypeScript 编写组件,并利用 TypeScript 提供的类型检查和智能提示功能。

8)React 设计思路,它的理念是什么?

React 的设计思路主要包括以下几个核心理念:

  • 虚拟 DOM: React 使用虚拟 DOM 来提高性能。虚拟 DOM 是在内存中对真实 DOM 的一种轻量级表示,通过比较虚拟 DOM 的差异来最小化实际 DOM 操作,从而提高渲染效率。
  • 单向数据流: React 强调单向数据流,即数据的流动是单向的,从父组件传递到子组件。这有助于更容易追踪和理解数据的变化,同时也使得组件更容易被复用。
  • 组件化: React 提倡组件化开发,将用户界面划分为小而独立的组件,每个组件负责自己的状态和渲染逻辑。这种模块化的设计使得代码更易维护、测试和复用。
  • 声明式编程: React 采用声明式编程风格,开发者只需描述目标的状态,而非步骤如何实现。这使得代码更易读、理解和维护。
  • 状态提升: React 鼓励将共享状态提升到最近的共同祖先组件,以保持组件之间的数据同步。这有助于避免状态的不一致性问题。

总体而言,React 的设计思路旨在提供一种简洁、高效、易于理解和维护的方式来构建用户界面,通过引入虚拟 DOM、单向数据流等概念来优化性能和开发体验。

9)React中props.children和React.Children的区别

  • props.children 是一个特殊的 prop,表示组件的所有子节点。当在 JSX 中使用组件时,该组件的所有子元素会被作为 props.children 传递给该组件。在组件内部,你可以直接通过 props.children 访问和处理这些子节点。

    // ExampleComponent.js
    const ExampleComponent = (props) => {
      return (
        <div>
          {props.children}
        </div>
      );
    };
    
    // 使用 ExampleComponent
    <ExampleComponent>
      <p>Hello, world!</p>
    </ExampleComponent>
    
  • React.Children 是一个 React 提供的工具类,用于处理 props.children。它提供了一些方法,例如 React.Children.mapReact.Children.forEach 等,用于遍历和处理 props.children 中的子元素。

    // 使用 React.Children.map 处理 props.children
    React.Children.map(props.children, child => {
      // 对每个子元素进行处理
    });
    

总的来说,props.children 是一个用于接收和直接访问子元素的 prop,而 React.Children 提供了一些工具方法,使得在处理 props.children 时更加方便。

10)React的状态提升是什么?使用场景有哪些?

状态提升(Lifting State Up): 状态提升是指将组件的状态移动到该组件的共同祖先组件中。通过将状态提升到更高层级的组件,可以确保共享状态的一致性,并且使得状态变化更易于追踪和管理。

使用场景:

  1. 共享状态: 当多个组件需要访问和共享相同的状态时,将这个状态提升到它们的最近共同祖先组件中。这样,所有子组件都可以通过 props 访问并修改这个状态。
  2. 避免状态不一致: 当多个组件需要依赖相同的状态进行渲染时,通过状态提升可以避免状态不一致的问题。所有组件都使用相同的状态,保持视图的一致性。
  3. 简化组件逻辑: 将状态提升可以使得每个组件的逻辑更简单,因为它们只需要关注自己的渲染和交互,而共享状态的管理由父组件负责。
  4. 提高可维护性: 状态提升使得状态集中管理,提高了代码的可维护性。在一个地方修改状态会影响所有依赖于该状态的组件。

例子:

// 状态提升前
const ParentComponent = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <ChildComponent count={count} setCount={setCount} />
      <AnotherChildComponent count={count} />
    </div>
  );
};

// 状态提升后
const ParentComponent = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <ChildComponent count={count} setCount={setCount} />
      <AnotherChildComponent count={count} setCount={setCount} />
    </div>
  );
};

在这个例子中,将 count 状态提升到 ParentComponent,使得两个子组件都可以访问和修改相同的状态。这样就避免了状态不一致的问题,同时也使得组件的逻辑更加清晰。

开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system

已 300 + Star!

⭐点赞⭐收藏⭐不迷路!⭐

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐