2023 version of the latest and most complete React interview questions

React, as the most used front-end framework, must be the focus of the interview. Next, we will mainly summarize from several conveniences such as the use of React, the source code level, and the surrounding ecology (such as redux, react-router, etc.).

1. In terms of usage

The main investigation here is the understanding of the React framework during the development and use process, such as the results obtained by different calling methods of hooks, the difference between useState in function components and state in class components, and so on.

Will the change of props cause the data in the state hook to change?

A change in the props of a React component will cause the component to re-execute, but it will not cause a change in the value of the state. The change of state value can only be triggered by setState(). Therefore, if you want to reset the state data when props change, you need to monitor the change of props, such as:

const App = props => {
  const [count, setCount] = useState(0);

  // 监听 props 的变化,重置 count 的值
  useEffect(() => {
    setCount(0);
  }, [props]);

  return <div onClick={() => setCount(count + 1)}>{count}</div>;
};

What's new in React18?

React updates are all incremental updates. The new features enabled in React18 are actually buried in v17 (or even earlier).

  1. Concurrent rendering mechanism: Make appropriate adjustments to the rendering process according to the user's device performance and network speed to ensure that the React application remains interactive during the long-term rendering process, avoiding page freezes or unresponsive situations, thereby improving user performance. experience.
  2. New creation method: now it is necessary to createRoot()create a root node first, and then call the render()method by the root node;
  3. Automatic batching optimization: Batching: React groups multiple state updates into one re-render for better performance. (merge multiple setstate events); before v18, only batch processing was implemented in the event processing function. In v18, all updates will be automatically batched, including promise chains, setTimeout and other asynchronous codes and native event processing functions;
  4. startTransition: Actively lower the priority. For example, "keyword association for search engines", the user's input in the input box is expected to be real-time, and the associated words can be delayed for a while. We can use startTransition to lower the priority of associative vocabulary updates;
  5. useId: Mainly used for SSR server-side rendering scenarios, which is convenient for generating unique ids during server-side rendering and client-side rendering;

How is concurrent mode implemented?

In React 并发, it does not mean doing multiple things at the same time. Because js itself is single-threaded (only one thing can be executed at the same time), and it has to compete with UI rendering for the main thread. If a time-consuming task occupies the thread, subsequent execution will be blocked. In order to avoid this situation, React uses the fiber structure and time slicing mechanism to decompose a large task into multiple small tasks, and then schedules the tasks according to the priority of the task and the occupation of the thread.

  • For each update, assign a priority lane to distinguish its urgency.
  • The non-urgent updates are split into multiple updates through the Fiber structure, and are reasonably allocated to the browser frames through macro tasks. This enables urgent tasks to be inserted.
  • A high-priority update will interrupt a low-priority update, and the low-priority update will start after the high-priority update is completed.

What are controlled and uncontrolled components?

Let's have a little understanding of what are controlled components and uncontrolled components:

  • Controlled component: A component that can only modify data or state through React is a controlled component;
  • Uncontrolled components: Contrary to controlled components, such as input, textarea, select, checkbox and other components, the control itself can control the changes of data and state, and React does not know these changes;

So how to change uncontrolled components to controlled components? That is to hand over the above pure html component data or state changes to React for operation:

const App = () => {
  const [value, setValue] = useState('');
  const [checked, setChecked] = useState(false);

  return (
    <>
      <input value={value} onInput={event => setValue(event.target.value)} />
      <input type="checkbox" checked={checked} onChange={event => setChecked(event.target.checked)} />
    </>
  );
};

In the above code, the changes of the input box and checkbox are all operated by React, and React can know when the data changes.

Higher Order Components (HOCs)?

HOC?

Higher-order components are passed in by wrapping React components, after a series of processing, and finally return a relatively enhanced React component for other components to call.

effect:

  1. Reuse logic: High-level components are more like a factory for processing react components, processing and packaging original components in batches. We can customize the exclusive HOC according to business needs, which can solve the reuse logic.
  2. Strengthen props: This is one of the most commonly used usages of HOC. The components returned by high-level components can hijack the props passed from the previous layer, and then mix in new props to enhance the function of the component. The representative is withRouter in react-router.
  3. Enabling components: HOC has a unique feature, that is, it can provide some extended functions for business components wrapped by HOC, such as additional life cycles and additional events, but this kind of HOC may need to be closely integrated with business components. The keepaliveLifeCycle in the typical case react-keepalive-router is to add an additional life cycle to the business component through the HOC method.
  4. Controlling rendering: Hijacking rendering is a feature of hoc. In the wrapComponent packaging component, you can perform conditional rendering, throttling rendering, lazy loading and other functions on the original component, which will be explained in detail later. Typical representatives are connect and dva in react-redux The dynamic components in the middle are lazy loaded.

Reference: react advanced "A thorough understanding of React high-level components (HOC)

Why use Hook in React?

The official website has introduced the reason: the motivation for using Hook .

Here we briefly refine:

  1. It is difficult to reuse state logic between components: in class components, render props and higher-order components may be required, but it will form a "nested region"; and using Hook, state logic can be extracted from components, which is These logics can be tested separately and reused;
  2. Complex components become difficult to understand: In class components, each life cycle often contains some unrelated logic. For example, different execution logics must be componentDidMountexecuted and acquired in , and then need to be  componentWillUnmount cleared in ; but in function components, different logics can be executed in different Hooks without interfering with each other;
  3. Incomprehensible class: Class components are full of various pairs  this , such as  this.onClick.bind(this), this.state, this.setState() etc. At the same time, class cannot be compressed well, and it will make hot reloading unstable; Hook makes you use non-class Cases can use more React features;

Usage scenarios of useCallback and useMemo

useCallback and useMemo can be used to cache functions and variables to improve performance and reduce resource waste. But not all functions and variables need to be implemented with these two, and it also has corresponding usage scenarios.

We know that useCallback can cache the function body. When there is no change in dependencies, the function body used is the same in the two renderings. Its usage scenarios are:

  • When the function is a dependency of other hooks (such as in useEffect());
  • Functions as props of components in React.memo() (or shouldComponentUpdate);

Mainly to avoid regenerated functions that cause unnecessary refreshes of other hooks or components.

useMemo is used to cache the result of function execution. If you need to perform a complex operation every time you render, or if a variable needs to depend on the result of another variable, you can use useMemo().

Reference article: useCallback and useMemo of React18 source code analysis .

What is the difference between the parameter passing method of useState?

There are two ways to pass parameters to useState(): pure data and callback function. When the two are initialized, there is no difference except that the input method is different. However, when calling, the output results are different depending on the calling method and the environment.

like:

const App = () => {
  const [count, setCount] = useState(0);

  const handleParamClick = () => {
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
  };

  const handleCbClick = () => {
    setCount(count => count + 1);
    setCount(count => count + 1);
    setCount(count => count + 1);
  };
};

For the above two input methods, the final count results are different. why? Because when passing parameters in the format of data, these three use the same count variable, and the values ​​are the same. It is equivalent setCount(0 + 1)to calling 3 times; but in the way of passing parameters of the callback function, React will generally directly call the callback function, and then get the latest result and store it inside React, so that it will be the latest when it is used next time. Note: This latest value is saved inside React, and the external count will not be updated immediately, it will only be updated after the next rendering.

Also, in the timer, the results obtained by the two are also different:

const App = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(count + 1);
    }, 500);
    return () => clearInterval(timer);
  }, []);

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(count => count + 1);
    }, 500);
    return () => clearInterval(timer);
  }, []);
};

Why do components render twice when developing locally?

issues#2

In React.StrictMode mode, if you use Hooks such as useState, usesMemo, and useReducer, React will deliberately render twice in order to expose some errors that are not easy to find. will be rendered repeatedly.

That is, in the strict mode of the test environment, it will be rendered twice.

How to implement lazy loading of components

Starting from 16.6.0, React provides lazy and Suspense to implement lazy loading.

import React, { lazy, Suspense } from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <OtherComponent />
    </Suspense>
  );
}

The property fallbackrepresents the rendered content before loading the component.

How to implement a timer hook

If you use React code directly in the timer, you may receive unexpected results. If we want to implement a timer that increments by 1 every second:

const App = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(timer);
  }, []);

  return <div className="App">{count}</div>;
};

It can be seen that after coun changes from 0 to 1, it will never change again. why?

Although the component will always re-render due to the existence of the timer, the callback function of the timer is defined during the mount, so its closure is always a reference to the Counter scope at the time of mount, so the count will never exceed 1.

For this single hook call, it is relatively easy to solve, for example, you can monitor the change of count, or pass parameters through the callback of useState.

const App = () => {
  const [count, setCount] = useState(0);

  // 监听 count 的变化,不过这里将定时器改成了 setTimeout
  // 即使不修改,setInterval()的timer也会在每次渲染时被清除掉,
  // 然后重新启动一个新的定时器
  useEffect(() => {
    const timer = setTimeout(() => {
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(timer);
  }, [count]);

  // 以回调的方式
  // 回调的方式,会计算回调的结果,然后作为下次更新的初始值
  // 详情可见: https://www.xiabingbao.com/post/react/react-usestate-rn5bc0.html#5.+updateReducer
  useEffect(() => {
    const timer = setInterval(() => {
      setCount(count => count + 1);
    }, 1000);
    return () => clearInterval(timer);
  }, []);

  return <div className="App">{count}</div>;
};

Of course, there are other ways to update the count. So what if more hooks are called, or more complicated code? Here we can encapsulate a new hook to use:

// https://overreacted.io/zh-hans/making-setinterval-declarative-with-react-hooks/
const useInterval = (callback: () => void, delay: number | null): void => {
  const savedCallback = useRef(callback);

  useEffect(() => {
    savedCallback.current = callback;
  });

  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      const id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
};

What is the cleanup mechanism of useEffect()? When will it be executed?

In the callback function of useEffect(callback), if there is a returned function, this is an optional clearing mechanism for effect. Each effect can return a cleanup function.

When does React clear the effect? React will perform cleanup when the component is unmounted. At the same time, if the component is updated, the previous cleanup function will be executed first, and then the next effect will be run. like

// 运行第一个 effect

// 产生更新时
// 清除上一个 effect
// 运行下一个 effect

// 产生更新时
// 清除上一个 effect
// 运行下一个 effect

// 组件卸载时
// 清除最后一个 effect

Reference: Why do you need to run Effect every time you update

2. At the source code level

This part of the investigation is more in-depth. You have to understand some source codes to understand the reasons, such as React's diff comparison, the role of keys in the loop, and so on.

What are the advantages of virtual dom? Real dom and virtual dom, who is faster?

Virtual DOM describes real dom objects in the form of objects, so when doing some updates, you can compare data in memory, reduce operations on real dom, reduce the number of browser rearrangement and redrawing, and reduce browser The pressure to improve the performance of the program, and because the difference comparison of the diff algorithm records the difference, then it will help the programmer reduce the mental burden on the difference during development, and improve the development efficiency.

There are so many virtual doms, is the rendering speed faster than directly operating the real dom? Not really. The virtual dom adds a layer of memory operations before manipulating the real dom and rendering the data to the page. Rendering will definitely be slower. Although the disadvantage of virtual dom is that it increases the memory calculation during initialization and increases the rendering time of the home page, but the calculation time is calculated in milliseconds or microseconds, which does not have a great impact on user experience.

What are synthetic events and how are they different from native events?

All triggered events in React encapsulate a set of event mechanisms within it. The purpose is to achieve browser-wide consistency and smooth out the differences between different browsers.

Before React17, React delegated events to the document. React17 and later versions no longer delegate events to the document, but to the mounted container. React synthetic events use the event bubbling mechanism. When an event is triggered on a specific element, the event will not be actually executed until it bubbles to the top element where the event is mounted.

For native events, when an event is triggered by a specific element, the event will be executed immediately. Therefore, if you want to compare the timing of event triggering, the native event will be executed first, and the React synthetic event will be executed later.

What is the function of key?

Keys help React identify which elements have changed, such as being added or removed. So you should give each element in the array a definite identifier.

When the component is refreshed, React internally compares whether the element has changed according to the key and the type of the element. If there is a problem with the data selected as the key, an exception may occur during the update process.

Reference: The role of key in React18 source code analysis .

Will executing useState() multiple times trigger multiple updates?

In React18, whether it is multiple useState() hooks or multiple data operations (dispatch). As long as they are at the same priority, React will merge them together and update the data at the end.

This is based on the batch processing mechanism of React18. React groups multiple state updates into one re-render for better performance. (merge multiple setstate events); before v18, only batch processing was implemented in the event processing function. In v18, all updates will be automatically batched, including promise chains, setTimeout and other asynchronous codes and native event processing functions;

Reference: Calling the dispatch method in useState() multiple times will result in multiple renderings?

Can the state of useState() be modified directly? Is it possible to cause the component to render?

First of all, we should not modify the value of state directly. On the one hand, the component cannot be refreshed (new data cannot be rendered into the page), and it may affect the next update.

The only thing that has an impact is that new data will be used where the variable is to be used later. But if other useState() causes the refresh of the component, the value of the variable just now, if it is a basic type (such as a number, a string, etc.), will be reset to the value before the modification; if it is a complex type, based on the object reference feature of js, it will also be The data stored inside React will be modified synchronously, but the view will not be changed.

Reference: What happens if you modify the value of state directly?

React's diff process

  1. React only compares nodes at the current level, not cross-level comparisons;
  2. Enter different processing functions according to different node types, such as function component nodes, class component nodes, ordinary fiber nodes, array nodes, etc.;
  3. Compare the two fiber nodes before and after. If the type is different, directly discard the old fiber node and create a new fiber node; if the key is different, you need to judge according to the situation. If it is a single element, directly discard it and create a new one Fiber node; if it is a digital element, check whether the position has been moved, if not found, create a new node; if the key and type are the same, then recurse down;
  4. If it is a single fiber node, it will return directly; if it is a fiber node with multiple elements in parallel, a one-way linked list will be formed here, and then the head pointer (the fiber node at the front of the linked list) will be returned;

Through the above diff comparison process, we can also see that when a component undergoes relatively large changes, React needs to do more actions to build a new fiber tree. Therefore, during the development process, if we optimize the performance In consideration of the perspective, it is especially important to note that:

  1. Do not generate a large number of leapfrog operations on nodes: because React only compares nodes at the same level, if a child node at the same position has a relatively large change, it will only discard the previous fiber node and execute the process of creating a new fiber node Operation; React will not move the previous fiber node to another location; correspondingly, after the previous jsx node is moved to another location, it will also perform more creation operations after comparing before and after;
  2. Do not modify the key and type of the node, such as using a random number as the key of the list, or changing the div tag to p tag, etc., during the diff comparison process, the previous fiber node and all child nodes will be directly discarded ( Even if the child node has not changed), and then recreate a new fiber node;

Reference: The process of generating fiber by reconcileChildren of React18 source code analysis

Based on the characteristics of the React framework, what optimization measures can be taken?

  1. Use React.lazy and Suspense to set the page as lazy loading to avoid too large js files;
  2. Use SSR isomorphic straight-out technology to improve the rendering speed of the first screen;
  3. Use useCallback and useMemo to cache functions or variables; use React.memo to cache components;
  4. Try to adjust the style or className changes, reduce the changes on the jsx elements, try to use the fields related to the elements as keys, which can reduce the diff time (React will try to reuse the previous nodes, if the jsx elements change, they need to be recreated node);
  5. For data that does not require page changes, it can be placed in useRef();

What is the difference between React.Children.map and js map?

The map in JavaScript will not handle null or undefined data, but the map in React.Children.map can handle React.Children is null or undefined.

3. Surrounding ecology

This part mainly examines the understanding of the ecological support around React, such as the state management library redux, mobx, and the routing component react-router-dom.

What is the difference between react-router and react-router-dom?

api aspect

React-router: Provides the core api for routing. Such as Router, Route, Switch, etc., but does not provide APIs for dom operations for routing jumps;
React-router-dom: Provides APIs such as BrowserRouter, Route, Link, etc., which can trigger events to control routing through dom operations.
Link component will render an a tag; BrowserRouter and HashRouter components, the former uses pushState and popState events to build routes, and the latter uses hash and hashchange events to build routes.

use difference

react-router-dom extends the api that can operate dom on the basis of react-router. Both Swtich and Route import corresponding components from react-router and re-export them without any special treatment.
There is a dependency on react-router in the package.json dependency in react-router-dom, so there is no need to install react-router additionally.

What are the three principles that Redux follows?

  1. Single source of truth: The state of the entire application is stored in an object/state tree in a single store. A single state tree makes it easier to track changes over time and debug or inspect applications.
  2. The state is read-only: the only way to change the state is to trigger an action. Actions are plain JS objects that describe changes. Just as state is a minimal representation of data, the operation is a minimal representation of a change to data.
  3. Changes using pure functions: In order to specify how the state tree is transformed by operations, you need pure functions. Pure functions are those whose return value depends only on the values ​​of their arguments.

What do you mean by "single source of truth"?

Redux uses a "Store" to store the entire state of the program in one place. So the state of all components is stored in the Store, and they receive updates from the Store itself. A single state tree makes it easier to track changes over time and debug or inspect programs.

What are the advantages of Redux?

The advantages of Redux are as follows:

  • Predictability of results - Since there is always one source of truth, the store, there is no question of how to synchronize the current state with actions and other parts of the application.
  • Maintainability − Code becomes easier to maintain with predictable results and strict structure.
  • Server side rendering - you just pass the store created on the server to the client. This is useful for initial rendering and optimizes app performance for a better user experience.
  • Developer Tools - From actions to state changes, developers can track everything happening in the app in real time.
  • Community and Ecosystem - There is a huge community behind Redux which makes it even more fascinating. A large community of talented individuals has contributed to library improvements and developed various applications.
  • Ease of testing - Redux's code is mostly small, pure and self-contained functions. This makes the code testable and self-contained.
  • Organization - Redux spells out exactly how the code is organized, which makes the code more consistent and simple when used by the team.

4. Summary

React involves a lot of relevant knowledge points, and I will update it frequently.

 

Guess you like

Origin blog.csdn.net/LinkSLA/article/details/129547714