专业编程基础技术教程

网站首页 > 基础教程 正文

2025年最新最全面50个React JS面试问题及答案

ccvgpt 2024-11-24 12:29:20 基础教程 9 ℃

ReactJs 是一个用于构建用户界面的流行 JavaScript 库。它由 Facebook 维护,广泛用于构建 Web 应用程序、移动应用程序和其他用户界面。React 允许开发人员创建可重复使用的组件,这有助于使大型应用程序更易于管理和维护。它旨在高效、声明性和灵活,可用于创建复杂、动态的用户界面。

1. React 如何工作?

2025年最新最全面50个React JS面试问题及答案

React 会创建一个虚拟 DOM。当组件中的状态发生变化时,它首先会运行“diffing”算法,该算法会识别虚拟 DOM 中发生了哪些变化。第二步是协调,它会使用 diff 的结果更新 DOM。

2. 使用 React 有什么优点?

  • 要知道一个组件是如何渲染的很容易,只需要看看渲染函数。
  • JSX 让您能够轻松阅读组件代码。您还可以轻松查看布局或组件的插入/组合方式。
  • 您可以在服务器端渲染 React。这可以改善 SEO 和性能。
  • 很容易测试。
  • 您可以将 React 与任何您想要的框架一起使用,因为它只是一个视图层。

3. 展示组件和容器组件有什么区别?

展示组件关注的是事物的外观。它们通常仅通过 props 接收数据和回调。这些组件很少有自己的状态,但如果有,通常与 UI 状态有关,而不是数据状态。

当你的组件只接收 props 并将它们渲染到页面时,这就是stateless component,可以使用纯函数。这些也称为哑组件或展示组件。

容器组件更关心事物的运作方式。这些组件为展示组件或其他容器组件提供数据和行为。它们定义操作并将其作为回调提供给展示组件。它们通常也是有状态的,因为它们充当数据源。

4. 类组件和功能组件有什么区别?

类组件使用 ES6 类语法,并使用返回 React 元素的 render 方法扩展 React 组件。

带有钩子的函数组件是纯 JavaScript 函数,也会返回 React 元素。在引入钩子之前,函数组件是无状态的。

5. state 和 props 有什么区别?

状态是一种数据结构,在组件安装时以默认值开始。状态可能会随时间发生变化,主要是由于用户事件。

Props(properties 的缩写)是组件的配置。它们从上方接收,并且对于接收它们的组件而言是不可变的。组件无法更改其 props,但它负责将其子组件的 props 组合在一起。回调函数也可以作为 props 传入。

6. 有哪些不同的生命周期方法?

  • componentWillMount(已弃用)——这最常用于根组件中的应用程序配置。
  • componentDidMount- 在这里,您需要完成所有没有 DOM 就无法完成的设置,并开始获取所需的所有数据。此外,如果您想设置事件监听器等,这个生命周期钩子是执行此操作的好地方。
  • componentWillReceiveProps(已弃用) - 此生命周期作用于特定的 prop 变化来触发状态转换。
  • shouldComponentUpdate- 如果您担心浪费渲染,shouldComponentUpdate 是一个提高性能的好地方,因为它允许您在组件收到新的 prop 时防止重新渲染。shouldComponentUpdate 应该始终返回一个布尔值,并根据这个布尔值确定组件是否重新渲染。
  • componentWillUpdate(已弃用) - 很少使用。它可以代替 componentWillReceiveProps 用于同样具有 shouldComponentUpdate(但无法访问先前的 props)的组件。
  • componentDidUpdate- 也常用于响应 prop 或状态变化来更新 DOM。
  • componentWillUnmount- 使您可以取消任何传出的网络请求,或删除与该组件相关的所有事件监听器。

7.解释 React Hooks。

Hooks 可让您使用更多 React 功能,而无需使用类。您最有可能遇到的第一个 Hook 是

useState。useState 是一个 Hook,可让您将 React 状态添加到函数组件。它返回一个带有 getter 和 setter 的数组。

语法如下:

const [count, setCount] = React.useState(0);
<button onClick={() => setCount(count + 1)}>Increase Count</button>;

使用类组件时的等效效果是。

this.state = {
  count: 0,
};

<button onClick={() => this.setState({ count: this.state.count + 1 })}>
  Increase Count
</button>;

您最有可能遇到的下一个钩子是 useEffect。Effect Hook 允许您在函数组件中执行副作用。通过将空数组作为第二个参数传递给 useEffect 相当于使用 componentD

useEffect(() => {
  // do stuff when the component mounts
}, []);

8. 应该在 React 类组件的哪里发出 AJAX/API 请求?

componentDidMount是 React 组件中应发出 AJAX 请求的位置。此方法将在组件mounts(首次添加到 DOM)时执行。此方法在组件的生命周期内仅执行一次。重要的是,您无法保证 AJAX 请求在组件挂载之前已解析。如果没有,则意味着您将尝试在未挂载的组件上设置状态,这将不起作用。发出 AJAX 请求componentDidMount将保证有一个组件要更新。

9.什么是受控组件?

在 HTML 中,表单元素(例如<input>、<textarea>和)<select>通常会保持自己的状态并根据用户输入进行更新。当用户提交表单时,上述元素的值将随表单一起发送。在 React 中,它的工作方式有所不同。包含表单的组件将跟踪其状态下的输入值,并在每次触发回调函数(例如 onChange)时重新渲染组件,因为状态将更新。以这种方式由 React 控制值的输入表单元素称为controlled component。

10. React 中的 refs 有什么用处?

Refs 用于获取对 React 中 DOM 节点或组件实例的引用。使用 refs 的典型示例包括管理焦点/文本选择、触发命令式动画或与第三方 DOM 库集成。您应避免使用字符串 refs 和内联 ref 回调。React 建议使用回调 refs。

11. 什么是高阶组件?

高阶组件是一个接受组件并返回新组件的函数。HOC 允许您重用代码、逻辑和引导抽象。最常见的可能是 Redux 的连接函数。除了简单地共享实用程序库和简单组合之外,HOC 是在 React 组件之间共享行为的最佳方式。如果您发现自己在不同的地方编写了大量执行相同操作的代码,您可能能够将该代码重构为可重用的 HOC。

12. 使用箭头函数有什么优点?

  • 范围安全:在箭头函数出现之前,每个新函数都定义了自己的 this 值(如果是构造函数,则为新对象;如果是严格模式函数调用,则为未定义;如果函数被调用为“对象方法”,则为基对象,等等)。箭头函数不会创建自己的 this,而是使用封闭执行上下文的 this 值。
  • 紧凑性:箭头函数更易于阅读和编写。
  • 清晰度:当几乎所有东西都是箭头函数时,任何常规函数都会立即脱颖而出,用于定义范围。开发人员始终可以查找下一个上级函数语句来查看对象是什么。

13. 如何防止类组件渲染?

从组件的渲染方法返回 null 意味着不会显示任何内容,但它不会影响组件生命周期方法的触发。

如果组件重新渲染的次数是一个问题,那么有两个选项可用。在shouldComponentUpdate生命周期方法钩子中手动实现检查。

shouldComponentUpdate(nextProps, nextState){
  const allowRender = true;
  // Do some check here and assign decicison to allowRender
  return allowRender
}

或者使用 React.PureComponent 而不是 React.Component React.PureComponent 通过浅显的 prop 和 state 比较来实现 shouldComponentUpdate()。这可以避免使用相同的 props 和 state 重新渲染组件。

14. 渲染列表时,键是什么以及它的用途是什么?

键可帮助 React 识别哪些项目已更改、已添加或已删除。应为数组内的元素指定键,以赋予元素稳定的身份。选择键的最佳方法是使用一个字符串,该字符串可唯一地标识列表项在其兄弟项中的位置。大多数情况下,您会使用数据中的 ID 作为键。当您没有渲染项目的稳定 ID 时,您可以将项目索引用作键作为最后的手段。如果项目可以重新排序,则不建议使用索引作为键,因为那样会很慢。

15.`super(props)`的用途是什么?

子类构造函数在被调用之前不能使用 this super()。此外,如果是子类,则必须调用 ES2015 类构造函数super()。将 props 传递给的原因super()是为了让你能够this.props在构造函数中访问。

16.什么是 JSX?

JSX 是 JavaScript 的语法扩展,具有 JavaScript 的全部功能。JSX 生成 React elements。

您可以将任何 JavaScript 表达式嵌入到 JSX 中,只需将其括在花括号中即可。经过编译后,JSX 表达式将成为常规 JavaScript 对象。

这意味着您可以在if语句和内部使用 JSX for loops,将其分配给变量,将其作为参数接受,并从函数中返回它。

17. 使用 React.createElement 相当于以下哪一项?

const element = <h1 className="greeting">Hello, world!</h1>;
const element = React.createElement(
  "h1",
  { className: "greeting" },
  "Hello, world!"
);

18.什么是redux?

  • redux 的基本思想是将整个应用程序的状态保存在一个单独的存储中。该存储只是一个 javascript 对象。
  • 改变状态的唯一方法是从应用程序发送操作,然后为这些修改状态的操作编写减速器。
  • 整个状态转换都保存在 Reducer 内部,并且不应该有任何side-effects。

19.redux 中的 store 是什么?

  • store 是一个保存应用程序状态的 JavaScript 对象。除此之外,它还具有以下职责:
  • 允许通过 访问状态getState();。
  • 允许通过 更新状态dispatch(action);。
  • 通过 注册监听器subscribe(listener);。
  • 通过 返回的函数处理监听器的取消注册subscribe(listener)。

20. 动作器 (action) 和减速器 (reducer) 的区别。

  • 动作是普通的 javascript 对象。
  • 它们必须具有一种类型来指示正在执行的操作的类型。
  • 本质上,操作是将数据从您的应用程序发送到您的商店的信息的有效负载。
  • Reducer 只是一个纯函数,它接受先前的状态和动作,并返回下一个状态。

21.Redux Thunk 用于什么?

  • Redux thunk 是一个中间件,它允许您编写返回函数而不是动作的动作创建器。
  • 然后,如果满足某个条件,可以使用 thunk 来延迟动作的分派。这允许您处理动作的异步分派。

22. 编写一个自定义钩子,可用于消除用户输入的抖动。

//hook
const useDebounce = (value, delay) => {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timeout = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(timeout);
    };
  }, [value]);

  return debouncedValue;
};

//example
const Counter = () => {
  const [value, setValue] = useState(0);
  const lastValue = useDebounce(value, 1000);

  return (
    <div>
      <p>
        Current Value: {value} | Debounced Value: {lastValue}
      </p>
      <button onClick={() => setValue(value + 1)}>Increment</button>
    </div>
  );
};

23. 编写自定义钩子以将文本复制到剪贴板。

// hook
function useCopyToClipboard(content) {
  const [isCopied, setIsCopied] = useState(false);

  const copy = useCallback(() => {
    navigator.clipboard
      .writeText(content)
      .then(() => setIsCopied(true))
      .then(() => setTimeout(() => setIsCopied(false), 1250))
      .catch((err) => alert(err));
  }, [content]);
  return [isCopied, copy];
}

// usage
export default function App() {
  const [isCopied, copy] = useCopyToClipboard("Text to copy!");
  return <button onClick={copy}>{isCopied ? "Copied!" : "Copy"}</button>;
}

24. 如何使用“useId”Hook 生成唯一的 ID。

  • useId 不接受任何参数。
  • useId 返回与此特定组件中的此特定 useId 调用相关联的唯一 ID 字符串。
//usage
import { useId } from "react";

const App = () => {
  const id = useId();

  return (
    <form>
      <label htmlFor={`email-${id}`}>Email</label>
      <input type="text" id={`email-${id}`} name="email" />

      <label htmlFor={`password-${id}`}>Password</label>
      <input type="password" id={`password-${id}`} name="password" />
    </form>
  );
};

//  Bad Practise - Don't use for key
const id = useId();

return posts.map((post) => <article key={id}>...</article>);

25. 如何在 React 中验证 Props?

  • 我们可以使用 'prop-types' 包
  • 之前,直到 React v15.5,它都是 React 本身的一部分
import PropTypes from "prop-types";

function MyComponent({ name }) {
  return <div>Hello, {name}</div>;
}

MyComponent.propTypes = {
  name: PropTypes.string,
};

export default MyComponent;

26. 给出一个 React 中高阶组件的实例。

当组件等待数据时显示加载器

//HOC
function WithLoading(Component) {
  return function WihLoadingComponent({ isLoading, ...props }) {
    if (!isLoading) return <Component {...props} />;
    return <p>Please wait, fetching your data in no time...</p>;
  };
}
export default WithLoading;

//usage
import UserListComponent from "./UserListComponent.js"; //importing component
import WithLoading from "./withLoading.js"; //importing HOC
const ListWithLoading = WithLoading(UserListComponent); //connect component with HOC

const App = () => {
  const [loading, setLoading] = useState(true);
  const [users, setUsers] = useState([]);
  useEffect(() => {
    //fetch data
    const dataFromApi = ["this is coming from API call", "don't show loader"];
    //at this time loader will be shown in the UI using HOC
    //data fetched successfully
    setUsers([...dataFromApi]);
    setLoading(false);
  }, []);

  return <ListWithLoading isLoading={loading} users={users} />;
};

27. 为什么 React 的 useDeferredValue 钩子很有用?

  • 'useDeferredValue' 是一个 React Hook,可让您推迟更新部分 UI。
  • 基本上,它让您用更少的代码执行去抖动技术。
//usage
import { useState, useDeferredValue } from "react";
//userList component takes searchText to fetch user's list
import UserList from "./UserList.js";

export default function App() {
  const [searchText, setSearchText] = useState("");
  //pass searchText as default visible value in useDeferredValue
  const deferredQuery = useDeferredValue(searchText);

  return (
    <>
      <label>
        Search user:
        <input
          value={searchText}
          onChange={(e) => setSearchText(e.target.value)}
        />
      </label>
      <div>
        <UserList searchText={deferredQuery} />
      </div>
    </>
  );
}

29. 如何检测 React 组件外部的“点击”?

export default function OutsideAlerter() {
  const clickMeDivRef = useRef(null);

  useEffect(() => {
    const handleClickOutside = (event) => {
      if (!ref?.current?.contains(event.target)) {
        alert("You clicked outside of me!");
      }
    };

    // Bind the event listener
    document.addEventListener("mousedown", handleClickOutside);

    return () => {
      // Unbind the event listener on clean up
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [clickMeDivRef]);

  return <div ref={clickMeDivRef}>Clicked me?</div>;
}

30.为什么React组件名称必须以大写字母开头?

  • 在 JSX 中,小写标签名称被视为 HTML 标签。但是,带点(属性访问器)的小写标签名称则不是。
  • <person />编译为 React.createElement('person') (html 标签)
  • <Person />编译为 React.createElement(Person)
  • <obj.person />编译为 React.createElement(obj.person)
// Wrong! This is a component and should be in uppercase.
function person(props) {
  // Correct! This usage of <div> is correct because div is a valid element.
  return <div>{props.isLearning ? "Great!" : "Call Mom!"}</div>;
}

function App() {
  // Wrong! React thinks <person /> is a HTML tag because it's not capitalized.
  return <person isLearning={true} />;
}

// Correct! This is a component and should be capitalized
function Person(props) {
  // Correct! This usage of <div> is correct because div is a valid element.
  return <div>{props.isLearning ? "Great!" : "Call Mom!"}</div>;
}

function App() {
  // Correct! React knows <Person /> is a component because it's capitalized.
  return <Person isLearning={true} />;
}

31.npx 和 npm 有什么区别?

  • NPM 是一个包管理器,可用于安装 node.js 包。
  • NPX 是一个执行 node.js 包的工具。

无论您是全局安装还是本地安装该包,NPX 都会临时安装并运行它。如果您配置了 package.json 文件,NPM 也可以运行包。

因此,如果您想快速检查/运行节点包而不安装它 - 请使用 NPX。

'create-react-app' 是一个 npm 包,预计在项目生命周期中仅运行一次。因此,最好使用 npx 一步安装并运行它。

> npx create-react-app codinn
npM - Manager
npX - Execute

32. 组件安装到 UI 上后,如何将焦点设置在输入字段上?

import React, { useEffect, useRef } from "react";

const SearchPage = () => {
  const textInput = useRef(null);

  useEffect(() => {
    textInput.current.focus();
  }, []);

  return (
    <div>
      <input ref={textInput} type="text" />
    </div>
  );
};

33.如何使用最新版本的 React Router 以编程方式导航?

//old - v5
import { useHistory } from "react-router-dom";

function HomeButton() {
  let history = useHistory();
  history.push('/some/path') here
};

//new - v6+
import { useNavigate } from "react-router-dom";

function SignupForm() {
  let navigate = useNavigate();

  async function handleSubmit(event) {
    event.preventDefault();
    await submitForm(event.target);
    navigate("../success", { replace: true });
  }

  return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}

//or
import { redirect } from "react-router-dom";

const loader = async () => {
  const user = await getUser();
  if (!user) {
    return redirect("/login");
  }
};

34.什么是 React 状态批处理?猜猜输出结果。

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button
        onClick={() => {
          setNumber(number + 1);
          setNumber(number + 1);
          setNumber(number + 1);
        }}
      >
        +3
      </button>
    </>
  );
}

输出

  • 点击 '+3' -> 打印 '1'
  • 或者由于状态批处理概念,仅更新状态一次

为什么?

这使您可以更新多个状态变量而不会触发太多的重新渲染。

但如果您还是想更新呢?那就是 - 点击“+3”时需要打印 3。

将回调方法传递给setNumber。

setNumber((n) => n + 1);
return (
  <>
    <h1>{number}</h1>
    <button
      onClick={() => {
        setNumber((n) => n + 1);
        setNumber((n) => n + 1);
        setNumber((n) => n + 1);
      }}
    >
      +3
    </button>
  </>
);

35. 如何使用 React 路由器在兄弟组件之间传递数据?

使用 React Router hook 可以在 React 的兄弟组件之间传递数据useParams。

父组件(通常是 App.js 来定义路由)

<Route path="/user/:id" element={<User />} />
import { useParams } from "react-router-dom";

const User = () => {
  let { id } = useParams();

  useEffect(() => {
    console.log(`/user/${id}`);
  }, []);

  // .....
};

36. 如何使用 useContext hook 访问全局变量?

//1. create context
const GlobalLanguageContext = React.createContext(null);

const App = () => {
  const contextValue = { language: "EN" };

  return (
    //2. connect with all the child components under Provider
    //One time Config - Here in Provider's value prop you can pass
    //the value of your context global variable
    <GlobalLanguageContext.Provider value={contextValue}>
      <Child />
    </GlobalLanguageContext.Provider>
  );
};

const Child = () => {
  //3. use variable
  const { language } = React.useContext(GlobalLanguageContext);
  return <div>Application Language: {language}</div>;
};

37. useMemo 和 useCallback 有什么区别?

  • useCallback 为您提供函数渲染之间的引用相等性。 useMemo 为您提供值渲染之间的引用相等性。
  • useCallback 和 useMemo 都要求一个函数和一个依赖项数组。区别在于,当依赖项发生变化时,useCallback 返回其函数,而 useMemo 调用其函数并返回结果。
  • useCallback 返回其未调用的函数,以便您可以稍后调用它,而 useMemo 调用其函数并返回结果

38. 为什么你应该选择 vite 而不是 create-react-app?

  • Create React App (CRA) 长期以来一直是大多数开发人员搭建 React 项目和设置开发服务器的首选工具。它提供了无需配置的现代构建设置。
  • 但是,当项目规模增加时,我们发现开发和构建时间也会增加。这种缓慢的反馈循环会影响开发人员的生产力和幸福感。
  • 为了解决这些问题,生态系统中出现了一个新的前端工具:Vite。
  • 与 CRA 不同,Vite 不会在提供服务之前构建整个应用程序,而是按需构建应用程序。它还利用原生 ES 模块、esbuild 和 Rollup 的强大功能来缩短开发和构建时间。
  • Vite 是新一代、注重速度和性能的前端工具。
  • Vite 是一个开发服务器,它在原生 ES 模块的基础上提供了丰富的功能增强:快速热模块替换(HMR)、预捆绑、对 typescript、jsx 和动态导入的支持。
  • 将您的代码与 Rollup 捆绑在一起的构建命令,已预先配置为输出用于生产的优化静态资产。

39.react-router 有什么优点?

  • 主要的优点react-router是当点击另一个页面的链接时,页面不必刷新。
  • 它还允许我们使用浏览器的history功能,同时保留正确的应用程序视图。
  • 更好的用户体验,在不同组件之间切换时可以轻松实现动画和过渡。
  • React Routerdynamic routing用于确保路由按照用户请求实现。这也意味着所有必需的组件也都呈现,不会出现任何白屏闪烁或页面重新加载。
  • 主要成分有react-router:BrowserRouter,Routes,Route,Link。

40. 如何优化 ReactJS 应用程序的性能?

  • 一种方法是使用 shouldComponentUpdate 生命周期方法来防止组件不必要的重新渲染。
  • 另一种方法是使用 PureComponent 类,它通过对 props 和 state 进行浅比较来实现 shouldComponentUpdate。

另外,使用React.memo高阶组件可以优化功能组件的性能。

41. 在 ReactJs 中编写 CRUD 功能代码?

要使用钩子在 React 应用程序中实现 CRUD(创建、读取、更新、删除)功能,您可以使用 useState 钩子来管理应用程序的状态,并使用 useEffect 钩子来处理副作用,例如向服务器发出 API 调用来创建、读取、更新或删除数据。

下面是如何使用钩子在 React 组件中实现 CRUD 功能的示例:

import React, { useState, useEffect } from "react";

function App() {
  // useState hook to manage the state of our items
  const [items, setItems] = useState([]);

  // useEffect hook to fetch the items from an API
  useEffect(() => {
    fetch("https://my-api.com/items")
      .then((response) => response.json())
      .then((data) => setItems(data));
  }, []);

  // helper function to add a new item
  const addItem = (name) => {
    const newItem = { name };
    setItems([...items, newItem]);
  };

  // helper function to update an item
  const updateItem = (index, name) => {
    const updatedItems = [...items];
    updatedItems[index] = { name };
    setItems(updatedItems);
  };

  // helper function to delete an item
  const deleteItem = (index) => {
    const updatedItems = [...items];
    updatedItems.splice(index, 1);
    setItems(updatedItems);
  };

  // render the items in a list
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>
          {item.name}
          <button onClick={() => updateItem(index, "updated name")}>
            Update
          </button>
          <button onClick={() => deleteItem(index)}>Delete</button>
        </li>
      ))}
      <button onClick={() => addItem("new item")}>Add item</button>
    </ul>
  );
}

42. React 中的 hooks 是什么?为什么它们有用?

React 中的钩子是一种函数,它允许开发人员在不编写类的情况下使用状态和其他 React 功能。这使得可以在函数式组件中使用这些功能,与基于类的组件相比,函数式组件更容易编写和理解。

43. React 中使用哪些常见的 hooks?

React 中使用的一些常见钩子包括 useState、useEffect 和 useContext。useState 钩子允许功能组件具有本地状态,useEffect 钩子允许功能组件执行副作用,useContext 钩子允许功能组件从最近的上下文提供程序访问值。

44. 你能在基于类的组件内部使用钩子吗?

不可以,钩子只能在函数式组件中使用。如果您需要在基于类的组件中使用状态或其他 React 功能,则需要使用类组件。

45. 如何测试使用钩子的组件?

您可以使用 react-testing-library 包中的 act 实用程序来测试使用钩子的组件。此实用程序允许您模拟 React 协调过程的效果,这对于钩子正常工作必不可少。然后,您可以使用标准 Jest 或 Enzyme 断言来验证组件的行为。

46. useEffect hook 有什么用?

useEffect 钩子用于在功能组件中执行副作用。这可以包括数据获取、设置订阅或手动更改 DOM 等操作。useEffect 钩子在组件渲染后调用,可用于确保您的组件与任何相关数据或依赖项保持同步。

47.在 React 中创建一个简单的自定义钩子?

要在 React 中创建自定义钩子,可以使用 useState 钩子将本地状态添加到功能组件。以下是示例:

import { useState } from "react";

function useCounter() {
  const [count, setCount] = useState(0);

  function increment() {
    setCount(count + 1);
  }

  return { count, increment };
}

此钩子为组件添加了计数状态和增量函数。要在组件中使用此钩子,您可以在组件函数顶部调用它,如下所示:

function MyComponent() {
  const { count, increment } = useCounter();

  return (
    <div>
      <p>The count is {count}.</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

现在,每当单击增量按钮时,计数状态都会更新,并且组件将使用新值重新渲染。

48. useEffect 和 useLayoutEffect 有什么区别?

下面是如何在 React 组件中使用 useEffect 和 useLayoutEffect 的示例:

import React, { useState, useEffect, useLayoutEffect } from "react";

function MyComponent() {
  const [count, setCount] = useState(0);

  // useEffect runs after the render cycle has completed
  useEffect(() => {
    // This code will run every time the component renders,
    // after the render is complete.
    console.log("useEffect running");
  });

  // useLayoutEffect runs synchronously immediately after the render cycle
  useLayoutEffect(() => {
    // This code will run every time the component renders,
    // before the browser has a chance to paint the update to the screen.
    // Be careful! This can cause visual inconsistencies.
    console.log("useLayoutEffect running");
  });

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

在此示例中,单击“增量”按钮时,useEffect 钩子将在组件更新并重新渲染后运行,而 useLayoutEffect 钩子将在更新绘制到屏幕之前运行。这意味着,如果您使用 useLayoutEffect 更新 UI,用户可能会在更新完成之前看到 UI 更新,这可能会导致视觉不一致。另一方面,useEffect 在更新完成后运行,因此用于更新 UI 更安全。

49.为什么虚拟DOM比真实DOM更新更快?

  • 虚拟 DOM 比真实 DOM 更新速度更快,因为 React 使用了一种巧妙的技术来最大限度地减少需要对真实 DOM 进行的更新次数。
  • 当你更新虚拟 DOM 时,React 会将新的虚拟 DOM 与旧的虚拟 DOM 进行比较,确定哪些部分发生了变化,然后相应地更新真实 DOM。这意味着只更新 DOM 中真正需要更改的部分,这比每次发生更改时更新整个 DOM 要快得多。
  • 此外,虚拟 DOM 是用 JavaScript 实现的,其执行速度通常比用于操作真实 DOM 的本机代码更快。
  • 这意味着 React 可以快速对虚拟 DOM 进行更新,然后使用生成的 diff 对真实 DOM 进行高效更新。
  • 总的来说,使用虚拟 DOM 可以让 React 高效地更新 UI,从而带来更快、响应更快的用户体验。

50. 你能解释一下纯函数和非纯函数之间的区别吗?以及为什么它在 React 环境中很重要?

在 React 中,纯函数是指无论何时调用,对于同一组输入都会返回相同输出的函数。另一方面,非纯函数是指对于同一组输入可能会产生不同输出的函数,具体取决于调用时间或其他因素。

以下是 React 中纯函数的一个示例:

function addNumbers(a, b) {
  return a + b;
}

此函数接受两个数字 a 和 b,并返回它们的和。无论何时调用或组件处于何种状态,此函数始终会针对相同的输入返回相同的结果。

以下是 React 中非纯函数的一个例子:

function getRandomNumber() {
  return Math.random();
}

此函数每次调用时都会返回一个随机数。由于此函数的输出取决于其无法控制的因素(在本例中为当前时间和随机种子),因此它被视为非纯函数。

通常,React 更倾向于使用纯函数,因为它们更易于推理和测试。另一方面,非纯函数可能会引入不可预测的行为,并使您的代码更难理解。

Tags:

最近发表
标签列表