React 基础
1. React 的核心概念是什么?什么是 JSX?
答案:React 的核心概念包括:
- 组件(Components)
- Props
- State
- 生命周期(Lifecycle)
- 虚拟 DOM(Virtual DOM)
- 单向数据流
JSX 是 JavaScript 的语法扩展,它允许你在 JavaScript 文件中编写类似 HTML 的代码。JSX 产生 React "元素"。例如:
const element = <h1>Hello, world!</h1>;
JSX 不是必需的,但它使得编写 React 应用程序更加方便。
2. React 的虚拟 DOM 是如何工作的?
答案:虚拟 DOM 是 React 性能优化的关键。它的工作原理如下:
- 当应用状态改变时,整个 UI 会在虚拟 DOM 中重新渲染。
- 然后,差异算法(Diffing Algorithm)会找出虚拟 DOM 中的变化。
- 计算完成后,只有变化的部分会被更新到实际的 DOM 中。
这个过程称为协调(Reconciliation)。通过这种方式,React 可以最小化 DOM 操作,从而提高性能。
3. 什么是 React 组件?函数组件和类组件有什么区别?
答案:React 组件是 UI 的可重用部分。它们可以接收输入(称为 "props")并返回描述屏幕上应该显示内容的 React 元素。
函数组件和类组件的主要区别:
语法:
- 函数组件:是一个返回 JSX 的 JavaScript 函数。
- 类组件:是一个扩展自 React.Component 的 JavaScript 类。
状态管理:
- 函数组件:在引入 Hooks 之前不能有状态,现在可以使用 useState Hook 管理状态。
- 类组件:可以使用 this.state 和 this.setState() 管理状态。
生命周期:
- 函数组件:使用 useEffect Hook 模拟生命周期。
- 类组件:有完整的生命周期方法。
性能:
- 函数组件通常更轻量,性能略好。
示例:
// 函数组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// 类组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
4. 什么是 Props?它们是如何在组件间传递的?
答案:Props(属性)是 React 组件之间传递数据的方式。它们是只读的,不应该被修改。Props 可以是任何 JavaScript 值,包括函数。
Props 的传递方式:
- 从父组件到子组件:在 JSX 中,像 HTML 属性一样传递。
- 从子组件到父组件:通过回调函数。
示例:
// 父组件
function Parent() {
const handleClick = () => console.log('Clicked!');
return <Child message="Hello" onClick={handleClick} />;
}
// 子组件
function Child(props) {
return (
<div>
<p>{props.message}</p>
<button onClick={props.onClick}>Click me</button>
</div>
);
}
5. 什么是 State?它与 Props 有什么不同?
答案:State 是组件内部管理的数据。与 Props 不同,State 可以被组件自身修改。
State 与 Props 的主要区别:
- 来源:Props 由父组件传入,State 在组件内部初始化和管理。
- 可变性:Props 是只读的,State 可以通过 setState(类组件)或 useState(函数组件)更新。
- 控制:Props 由父组件控制,State 由组件自身控制。
示例(使用 Hooks):
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
6. React 中的事件处理与原生 JavaScript 有什么不同?
答案:React 中的事件处理与原生 JavaScript 有几个主要区别:
- 命名:React 事件使用驼峰命名(例如 onClick),而不是全小写(onclick)。
- 传递函数:React 中你传递一个函数作为事件处理器,而不是字符串。
- 阻止默认行为:在 React 中,你不能通过返回 false 来阻止默认行为,必须明确调用 preventDefault。
- 合成事件:React 使用合成事件(SyntheticEvent)包装了浏览器的原生事件,提供了一致的属性和方法。
示例:
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
7. 什么是受控组件和非受控组件?
答案:
- 受控组件:表单数据由 React 组件控制。表单元素的值由 state 控制,每次 state 更新都重新渲染组件。
function ControlledInput() {
const [value, setValue] = useState('');
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
- 非受控组件:表单数据由 DOM 本身处理。通常使用 ref 来获取表单值。
function UncontrolledInput() {
const inputRef = useRef(null);
function handleSubmit() {
console.log(inputRef.current.value);
}
return (
<>
<input ref={inputRef} />
<button onClick={handleSubmit}>Submit</button>
</>
);
}
受控组件更符合 React 的数据流,但有时使用非受控组件可以减少代码量并提高性能。
8. 什么是 React 的生命周期方法?在函数组件中如何模拟生命周期?
答案:React 的生命周期方法是在组件不同阶段被调用的特殊函数。主要的生命周期方法包括:
- 挂载阶段:constructor, render, componentDidMount
- 更新阶段:render, componentDidUpdate
- 卸载阶段:componentWillUnmount
在函数组件中,我们使用 useEffect Hook 来模拟生命周期:
import React, { useEffect, useState } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
// 相当于 componentDidMount
useEffect(() => {
fetchData();
}, []);
// 相当于 componentDidUpdate
useEffect(() => {
console.log('data updated', data);
}, [data]);
// 相当于 componentWillUnmount
useEffect(() => {
return () => {
console.log('component will unmount');
};
}, []);
function fetchData() {
// 获取数据的逻辑
}
return <div>{/* 组件内容 */}</div>;
}
9. 什么是高阶组件(HOC)?它们有什么用途?
答案:高阶组件(HOC)是一个函数,它接受一个组件作为参数并返回一个新的组件。HOC 是 React 中复用组件逻辑的高级技术。
HOC 的主要用途:
- 代码复用
- 渲染劫持
- State 抽象和操作
- Props 操作
示例:
function withLogging(WrappedComponent) {
return class extends React.Component {
componentDidMount() {
console.log('Component is mounted');
}
render() {
return <WrappedComponent {...this.props} />;
}
};
}
// 使用
const EnhancedComponent = withLogging(MyComponent);
10. React 中的 key 属性有什么作用?
答案:在 React 中,key 是一个特殊的属性,主要用在列表渲染中。key 帮助 React 识别哪些项目被修改、添加或删除。
key 的作用:
- 提高渲染性能:React 使用 key 来优化元素的比对过程。
- 维护组件状态:正确的 key 可以帮助 React 在列表重新渲染时保持组件状态。
- 防止重复渲染:当列表顺序改变时,使用索引作为 key 可能导致不必要的重新渲染。
示例:
function List({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
注意:不推荐使用数组索引作为 key,除非列表是静态的且不会重新排序。最好使用稳定的、唯一的标识符作为 key。