基础概念类
1. 什么是 React?
React 是一个用于构建用户界面的 JavaScript 库,由 Facebook 开发并开源。它采用组件化的思想,允许开发者将复杂的 UI 拆分成多个小的、可复用的组件,通过组合这些组件来构建整个应用程序。React 使用虚拟 DOM(Virtual DOM)来提高渲染效率,通过比较新旧虚拟 DOM 的差异,只更新需要更新的真实 DOM 节点。
2. 什么是 JSX?它有什么作用?
JSX 是 JavaScript XML 的缩写,它是一种 JavaScript 的语法扩展,允许在 JavaScript 代码中编写类似 XML 的标记。JSX 的作用主要有:
- 更直观的 UI 描述:使代码更接近 HTML 结构,方便开发者编写和理解 UI 界面。
- 静态检查:可以在编译时进行静态检查,提前发现一些错误。
- 与 JavaScript 无缝集成:可以在 JSX 中嵌入 JavaScript 表达式,实现动态内容的展示。
示例:
const element = <h1>Hello, {name}!</h1>;
3. 什么是虚拟 DOM(Virtual DOM)?为什么要使用它?
虚拟 DOM 是一种轻量级的 JavaScript 对象,它是真实 DOM 的抽象表示。虚拟 DOM 是一个树形结构,每个节点对应一个真实的 DOM 元素。
使用虚拟 DOM 的原因:
- 提高性能:在更新 UI 时,直接操作真实 DOM 的代价较高。React 会先在虚拟 DOM 上进行修改,然后通过比较新旧虚拟 DOM 的差异,只更新需要更新的真实 DOM 节点,减少了真实 DOM 的操作次数,从而提高了性能。
- 跨平台:虚拟 DOM 是一个抽象的概念,不依赖于具体的平台,可以方便地实现跨平台开发,如 React Native 就是基于虚拟 DOM 实现的。
组件相关类
1. React 组件有哪几种类型?它们有什么区别?
React 组件主要分为两类:函数组件和类组件。
-
函数组件:是一个纯函数,接收
props
作为参数,并返回一个 React 元素。函数组件没有自己的状态和生命周期方法,也被称为无状态组件。
示例:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
-
类组件:是一个继承自
React.Component
的类,它有自己的状态和生命周期方法。类组件可以使用this.state
来管理组件的状态,通过this.props
接收外部传递的属性。
示例:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
区别:
-
状态管理:函数组件没有自己的状态,只能通过
props
接收外部数据;类组件可以使用this.state
管理组件的状态。 -
生命周期方法:函数组件没有生命周期方法;类组件有一系列的生命周期方法,如
componentDidMount
、componentDidUpdate
等。 - 代码复杂度:函数组件代码更简洁,适合简单的展示性组件;类组件代码相对复杂,适合处理复杂的逻辑和状态管理。
2. 什么是 props
和 state
?它们有什么区别?
-
props
:是properties
的缩写,用于在组件之间传递数据。props
是只读的,组件不能修改自己的props
,只能通过父组件重新传递新的props
来更新数据。 -
state
:是组件内部的状态,用于管理组件自身的数据。state
是可变的,组件可以通过this.setState
方法来更新state
,从而触发组件的重新渲染。
区别:
-
数据来源:
props
是从父组件传递过来的;state
是组件内部自己管理的数据。 -
可变性:
props
是只读的;state
是可变的。 -
使用场景:
props
用于在组件之间传递数据;state
用于管理组件内部的动态数据。
3. 如何在 React 中实现组件间通信?
-
父组件向子组件通信:通过
props
传递数据。父组件将数据作为属性传递给子组件,子组件通过props
接收数据。
示例:
// 父组件
function Parent() {
const message = "Hello from parent";
return <Child message={message} />;
}
// 子组件
function Child(props) {
return <p>{props.message}</p>;
}
-
子组件向父组件通信:通过回调函数。父组件将一个回调函数作为
props
传递给子组件,子组件在需要时调用该回调函数并传递数据给父组件。
示例:
// 父组件
function Parent() {
const handleChildData = (data) => {
console.log(data);
};
return <Child onData={handleChildData} />;
}
// 子组件
function Child(props) {
const sendData = () => {
props.onData("Hello from child");
};
return <button onClick={sendData}>Send Data</button>;
}
- 非父子组件通信:可以使用事件总线(Event Bus)、Context API 或状态管理库(如 Redux、MobX)来实现。
生命周期与 Hooks 类
1. 简述 React 类组件的生命周期方法。
React 类组件的生命周期方法可以分为三个阶段:挂载阶段、更新阶段和卸载阶段。
-
挂载阶段:组件被创建并插入到 DOM 中。
-
constructor
:组件的构造函数,用于初始化state
和绑定事件处理函数。 -
static getDerivedStateFromProps
:在组件挂载和更新时都会调用,用于根据props
更新state
。 -
render
:渲染组件的 UI。 -
componentDidMount
:组件挂载完成后调用,常用于发起网络请求、订阅事件等。
-
-
更新阶段:组件的
props
或state
发生变化时,组件会重新渲染。-
static getDerivedStateFromProps
:同上。 -
shouldComponentUpdate
:用于决定组件是否需要重新渲染,返回true
表示需要重新渲染,返回false
表示不需要。 -
render
:同上。 -
getSnapshotBeforeUpdate
:在 DOM 更新之前调用,用于获取 DOM 更新前的一些信息。 -
componentDidUpdate
:组件更新完成后调用,常用于更新 DOM 或发起网络请求。
-
-
卸载阶段:组件从 DOM 中移除。
-
componentWillUnmount
:组件卸载前调用,常用于清理定时器、取消订阅等操作。
-
2. 什么是 React Hooks?常见的 Hooks 有哪些?
React Hooks 是 React 16.8 引入的新特性,它允许在不编写 class
的情况下使用 state
和其他 React 特性。Hooks 可以让你在不改变组件结构的情况下复用状态逻辑,使代码更加简洁和可维护。
常见的 Hooks 有:
-
useState
:用于在函数组件中添加state
。
示例:
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
-
useEffect
:用于在函数组件中处理副作用,如数据获取、订阅、定时器等。
示例:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
return () => {
// 清理副作用
};
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
-
useContext
:用于在函数组件中使用 Context API。 -
useReducer
:是useState
的替代方案,用于处理复杂的状态逻辑。 -
useCallback
:用于缓存函数,避免在每次渲染时都重新创建函数。 -
useMemo
:用于缓存计算结果,避免在每次渲染时都进行复杂的计算。
3. useState
和 useReducer
有什么区别?
-
使用场景:
-
useState
适用于简单的状态管理,状态的更新逻辑比较简单,通常只涉及到对状态的简单修改。 -
useReducer
适用于复杂的状态管理,状态的更新逻辑比较复杂,涉及到多个状态的组合或复杂的计算。
-
-
语法:
-
useState
使用一个初始值来初始化状态,并返回一个数组,数组的第一个元素是当前状态,第二个元素是更新状态的函数。 -
useReducer
使用一个 reducer 函数和一个初始状态来初始化状态,并返回一个数组,数组的第一个元素是当前状态,第二个元素是触发状态更新的 dispatch 函数。
-
示例:
// useState
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
// useReducer
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
</div>
);
}
性能优化类
1. 如何优化 React 应用的性能?
-
使用
shouldComponentUpdate
或React.memo
:shouldComponentUpdate
是类组件的生命周期方法,用于决定组件是否需要重新渲染;React.memo
是函数组件的高阶组件,用于浅比较props
,如果props
没有变化,则不会重新渲染组件。 -
使用
React.lazy
和Suspense
:React.lazy
用于动态导入组件,Suspense
用于在组件加载时显示加载提示,实现代码分割,减少首屏加载时间。
示例:
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<React.Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</React.Suspense>
</div>
);
}
-
避免不必要的渲染:尽量减少
state
和props
的变化,避免在render
方法中进行复杂的计算。 - 使用事件委托:将事件处理函数绑定到父组件上,通过事件冒泡来处理子组件的事件,减少事件处理函数的数量。
- 优化 CSS:避免使用内联样式,使用 CSS 类名来管理样式,减少重排和重绘。
2. 什么是 React.memo?它和 shouldComponentUpdate
有什么区别?
-
React.memo
:是一个高阶组件,用于函数组件的性能优化。它会对组件的props
进行浅比较,如果props
没有变化,则不会重新渲染组件。
示例:
const MyComponent = React.memo((props) => {
return <div>{props.message}</div>;
});
-
区别:
-
适用组件类型:
React.memo
适用于函数组件;shouldComponentUpdate
适用于类组件。 -
比较方式:
React.memo
进行浅比较;shouldComponentUpdate
可以自定义比较逻辑,进行更复杂的比较。
-
适用组件类型:
其他类
1. 什么是 React Router?如何使用它实现路由功能?
React Router 是 React 官方推荐的路由库,用于实现单页面应用(SPA)的路由功能。它提供了不同的路由组件,如 BrowserRouter
、HashRouter
、Route
、Link
等。
使用步骤:
- 安装 React Router:
npm install react-router-dom
- 引入必要的组件:
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
- 创建路由配置:
function App() {
return (
<Router>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
</ul>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Router>
);
}
function Home() {
return <h1>Home Page</h1>;
}
function About() {
return <h1>About Page</h1>;
}
2. 什么是 Context API?它有什么作用?
Context API 是 React 提供的一种在组件树中共享数据的方式,避免了通过 props
层层传递数据的繁琐。它主要用于在多个组件之间共享一些全局数据,如用户信息、主题颜色等。
使用步骤:
- 创建 Context:
const MyContext = React.createContext();
- 提供数据:
<MyContext.Provider value={/* 要共享的数据 */}>
{/* 子组件 */}
</MyContext.Provider>
- 消费数据:
// 类组件
class MyComponent extends React.Component {
static contextType = MyContext;
render() {
const value = this.context;
return <div>{value}</div>;
}
}
// 函数组件
function MyComponent() {
const value = useContext(MyContext);
return <div>{value}</div>;
}