React 概念:深入指南
React 是一个强大的 JavaScript 库,用于构建交互式用户界面。下面我们将详细介绍每一个主要的 React 概念,并提供详细的代码示例,逐步进行讲解。
1. 组件
- 定义:组件是任何 React 应用的构建块。它们是可复用的 UI 单元,封装了逻辑、标记和样式。
- 类型:主要有两种类型:
- 函数组件:使用 JavaScript 函数创建的组件。从 React 16.8 开始,可以通过 hooks 使用状态和其他 React 特性。
- 类组件:JavaScript 类,继承自
React.Component
。这些组件在 hooks 出现之前更为常用。
- 为何使用组件:组件帮助将 UI 分解为更小、更易于管理的部分,使代码更具复用性、更易于维护和测试。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11// 函数组件示例
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
// 类组件示例
class Welcome extends React.Component {
render() {
return <h1>Welcome, {this.props.name}!</h1>;
}
}
2. JSX (JavaScript XML)
- 定义:JSX 是一种语法扩展,看起来像是 HTML 和 JavaScript 的混合。它允许开发者在 JavaScript 中直接编写 UI 模板。
- 为何使用 JSX:将标记和逻辑结合,使代码更易读。JSX
在底层被编译为
React.createElement()
函数调用。 - 代码示例:
1
2
3const element = <h1>Hello, world!</h1>;
// 编译为:
const element = React.createElement('h1', null, 'Hello, world!');
3. Props (属性)
- 定义:Props 是组件的输入,用于在组件之间传递数据。
- 不可变性:Props 是只读的。它们允许组件接收动态数据,并由父组件传递给子组件。
- 代码示例:
1
2
3
4
5
6
7function Button(props) {
return <button onClick={props.onClick}>{props.label}</button>;
}
function App() {
return <Button label="Click me" onClick={() => alert('Button clicked!')} />;
}
4. State (状态)
- 定义:State 是一个内置的 React 对象,用于存储组件生命周期中可能变化的数据。
- 与 Props 的区别:与 Props 不同,State 是可变的,并在组件内部管理。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11import 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>
);
}
5. 生命周期方法 (在类组件中)
- 定义:生命周期方法是在组件生命周期的特定时间运行的方法,比如组件挂载、更新或卸载时。
- 关键方法:
componentDidMount
:在组件添加到 DOM 后立即调用。componentDidUpdate
:在组件更新后运行,适合在状态或 props 更改后执行操作。componentWillUnmount
:在组件从 DOM 中移除之前调用。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Timer extends React.Component {
componentDidMount() {
this.timerID = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
console.log('Tick');
}
render() {
return <div>Timer is running...</div>;
}
}
6. Hooks
- 定义:Hooks 是一些函数,允许在函数组件中使用 React 的状态和其他特性。
- 常用 Hooks:
useState
:为函数组件添加状态。useEffect
:用于执行副作用操作,比如数据获取和订阅。useContext
:无需包装元素即可访问 React 上下文。
- 代码示例:
1
2
3
4
5
6
7
8
9
10import React, { useEffect } from 'react';
function DataFetcher() {
useEffect(() => {
// 模拟数据获取
console.log('Fetching data...');
}, []); // 空数组表示只在初次渲染时运行
return <div>Data fetched.</div>;
}
7. Context API
- 定义:Context API 允许组件共享值(如主题或用户数据),而无需通过每一层组件逐层传递 props。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function ThemedComponent() {
const theme = useContext(ThemeContext);
return <div>The current theme is {theme}</div>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedComponent />
</ThemeContext.Provider>
);
}
8. React Router
- 定义:React Router 是一个用于路由的库,帮助在不同组件之间导航而无需页面重新加载。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
function Home() {
return <h2>Home Page</h2>;
}
function About() {
return <h2>About Page</h2>;
}
function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</Router>
);
}
9. 状态管理
- 局部状态:由各个组件内部使用的状态,通过
useState
或setState
来管理。 - 全局状态:通过 Redux、Recoil 或 Context API 等工具管理,以在多个组件之间共享状态。
- Redux 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34import { createStore } from 'redux';
import { Provider, useDispatch, useSelector } from 'react-redux';
const initialState = { count: 0 };
function reducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
default:
return state;
}
}
const store = createStore(reducer);
function Counter() {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
</div>
);
}
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
10. 协调 (Reconciliation)
- 定义:React 在数据更改时,用于高效更新 UI 的过程。
- 虚拟 DOM:React 使用实际 DOM 的轻量级表示形式,使更改和更新更快。
- 代码示例:
1
// React 内部会对比虚拟 DOM,以找到需要更新的部分,并只对这些部分进行更新。
11. Keys
- 定义:为动态生成的元素(尤其是列表)提供唯一标识符。
- 为何使用 Keys:它们帮助 React 识别哪些项已更改、添加或删除,从而优化重新渲染。
- 代码示例:
1
2
3
4
5
6
7
8
9function ItemList({ items }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
12. 高阶组件 (HOCs)
- 定义:一个接受组件并返回一个新增强组件的函数。
- 为何使用 HOCs:它们允许在多个组件间复用逻辑,而无需重复代码。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12function withLogging(WrappedComponent) {
return function EnhancedComponent(props) {
console.log('Rendering component with props:', props);
return <WrappedComponent {...props} />;
};
}
function SimpleComponent({ message }) {
return <div>{message}</div>;
}
const EnhancedComponent = withLogging(SimpleComponent);
13. 错误边界 (Error Boundaries)
- 定义:用于捕获子组件树中任何 JavaScript 错误的组件。
- 使用场景:防止当某部分 UI 出错时导致整个应用崩溃,并提供备用 UI。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
console.log('Error caught:', error, info);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
function BuggyComponent() {
throw new Error('I crashed!');
}
function App() {
return (
<ErrorBoundary>
<BuggyComponent />
</ErrorBoundary>
);
}
14. 受控与非受控组件
- 受控组件:由 React 通过状态控制其值的输入元素。
- 非受控组件:数据由 DOM 本身处理,使用
ref
获取其值。 - 为何重要:受控组件提供了更多的控制,易于验证,而非受控组件在某些情况下更为简单。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import React, { useRef, useState } from 'react';
function ControlledInput() {
const [value, setValue] = useState('');
return (
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
function UncontrolledInput() {
const inputRef = useRef(null);
const handleSubmit = () => {
alert(`Input value: ${inputRef.current.value}`);
};
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleSubmit}>Submit</button>
</div>
);
}
15. Fragments (片段)
- 定义:Fragments 允许将多个子元素分组,而不向 DOM 添加额外的节点。
- 使用场景:避免添加不必要的包装
div
,从而生成更简洁的标记。 - 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import React from 'react';
function Table() {
return (
<table>
<tbody>
<tr>
<React.Fragment>
<td>Column 1</td>
<td>Column 2</td>
</React.Fragment>
</tr>
</tbody>
</table>
);
}
16. Portals (传送门)
- 定义:Portals 允许将子元素渲染到 DOM 树中的不同部分,脱离主组件层次结构。
- 使用场景:适用于模态框、工具提示或其他需要在父组件之外的 UI。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import React from 'react';
import ReactDOM from 'react-dom';
function Modal({ children }) {
return ReactDOM.createPortal(
<div className="modal">
{children}
</div>,
document.getElementById('modal-root')
);
}
function App() {
return (
<div>
<h1>Main Application</h1>
<Modal>
<p>This is a modal content!</p>
</Modal>
</div>
);
}
17. Memoization 和
React.memo
- 定义:
React.memo
是一个高阶组件,用于缓存结果,防止不必要的重新渲染。 - 为何使用缓存:提升性能,尤其是对重新渲染开销较大的组件。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import React from 'react';
const ExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {
console.log('Rendering ExpensiveComponent');
return <div>{data}</div>;
});
function App() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<ExpensiveComponent data="This is expensive!" />
</div>
);
}
18. 严格模式 (Strict Mode)
- 定义:一种仅在开发环境中使用的工具,用于帮助识别潜在问题,启用额外的检查。
- 如何使用:用
<React.StrictMode>
包裹应用或其部分。 - 好处:检测已弃用的特性、意外的副作用,帮助编写更好的代码。
- 代码示例:
1
2
3
4
5
6
7
8
9import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
19. 服务器端渲染 (SSR)
- 定义:在服务器上渲染组件并将 HTML 发送给客户端。
- 工具:像 Next.js 这样的流行框架支持 SSR。
- 好处:更快的初始页面加载、更好的 SEO、在低网络环境下性能更好。
- 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 在 Next.js 中实现 SSR
import React from 'react';
function Home({ data }) {
return <div>{data}</div>;
}
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return {
props: { data },
};
}
export default Home;
20. 代码分割和懒加载
- 代码分割:将应用拆分为较小的包,以减少初始加载时间。
- 懒加载:仅加载当前视图所需的代码。
- 工具:React 的
React.lazy()
和Suspense
帮助实现懒加载。 - 代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
总结
理解这些核心概念可以帮助你使用 React 开发高效、强大和可维护的应用程序。每个概念相互协作,增强开发者构建现代用户界面和 Web 应用的方式。