React 是由 Facebook 开发并维护的一个用于构建用户界面的 JavaScript 库。自2013年5月首次发布以来,React 因其高效性、灵活性和强大的生态系统而广受欢迎。React 不仅可以用于构建 Web 应用程序,还可以通过 React Native 构建移动应用程序。本文将详细介绍 React 的核心概念、生命周期方法、最新特性以及最佳实践,帮助读者全面掌握这一强大的前端工具。
React 的官方网站是 https://react.docschina.org/。在这里,你可以找到官方文档、教程、API 参考以及社区资源。
Create React App
是一个官方支持的脚手架工具,可以帮助你快速搭建一个 React 应用程序。以下是安装步骤:
node -v
npm -v
npx create-react-app my-app
cd my-app
npm start
这将启动一个本地开发服务器,并在浏览器中打开 http://localhost:3000
,你将看到一个默认的 React 应用程序。如果你不想使用 Create React App,也可以手动安装 React 和相关依赖。以下是步骤:
mkdir my-app
cd my-app
npm init -y
npm install react react-dom
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React Apptitle>
head>
<body>
<div id="root">div>
<script src="./index.js">script>
body>
html>
import React from 'react';
import ReactDOM from 'react-dom';
const App = () => {
return <h1>Hello, React!</h1>;
};
ReactDOM.render(<App />, document.getElementById('root'));
webpack
或其他模块打包工具来启动开发服务器。这里以 webpack
为例:npm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react
const path = require('path');
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
};
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
"scripts": {
"start": "webpack serve --open"
}
npm start
React 的核心理念之一是组件化。组件化意味着将复杂的用户界面分解为多个小的、可重用的组件。每个组件负责渲染一部分 UI,并且可以拥有自己的逻辑和状态。组件之间通过属性(Props)进行通信,形成树状结构。
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>;
}
}
JSX 是一种扩展语法,允许在 JavaScript 中编写类似于 HTML 的标记语言。实际上,JSX 会被编译成普通的 JavaScript 函数调用,通常是 React.createElement()
。
const element = <h1>Hello, world!</h1>;
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
虚拟 DOM 是 React 内部使用的轻量级 DOM 树副本。当组件的状态或属性发生变化时,React 会先在虚拟 DOM 上进行更改,然后通过高效的算法计算出最小的更新操作,最后将这些操作应用到真实的 DOM 上,从而减少不必要的 DOM 操作,提高性能。
function ChildComponent(props) {
return <div>{props.message}</div>;
}
function ParentComponent() {
return <ChildComponent message="Hello from parent!" />;
}
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
)
}
}
React 组件的生命周期可以分为三个主要阶段:挂载、更新和卸载。每个阶段都有相应的生命周期方法,这些方法可以在特定的时间点执行特定的操作。
constructor(props)
:构造函数,在组件实例创建时调用。static getDerivedStateFromProps(nextProps, prevState)
:静态方法,在每次渲染之前调用,用于根据新的 Props 更新 State。render()
:渲染方法,返回要显示的 UI。componentDidMount()
:组件挂载后调用,通常用于发起网络请求或设置定时器。static getDerivedStateFromProps(nextProps, prevState)
:在每次渲染前调用,用于根据新的 Props 更新 State。shouldComponentUpdate(nextProps, nextState)
:决定组件是否需要重新渲染,默认返回 true。render()
:重新渲染组件。getSnapshotBeforeUpdate(prevProps, prevState)
:在最近一次渲染输出(提交到 DOM 节点)之前调用,可以捕获 DOM 变化前的信息。componentDidUpdate(prevProps, prevState, snapshot)
:组件更新后调用,通常用于更新 DOM 或发起网络请求。componentWillUnmount()
:组件卸载前调用,用于清理定时器、取消网络请求等操作。Hooks 是 React 16.8 版本引入的新特性,允许在不编写类的情况下使用状态和其他 React 功能。Hooks 主要包括以下几种:
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>
)
}
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
})
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
)
}
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme }}>Themed Button</button>;
}
Context API 提供了一种在组件树中传递数据的方式,而无需手动地通过 Props 逐层传递。这对于大型应用中的全局状态管理非常有用。
const MyContext = React.createContext(defaultValue);
<MyContext.Provider value={value}>
{/* 子组件 */}
</MyContext.Provider>
<MyContext.Consumer>
{value => /* 基于 context 值的 UI */}
</MyContext.Consumer>
const value = useContext(MyContext);
在复杂的应用中,状态管理变得尤为重要。React 提供了几种不同的状态管理解决方案,包括但不限于:
Redux 是一个用于管理应用状态的库,常与 React 一起使用。它通过一个全局的 store 来集中管理应用的状态。
npm install redux react-redux
import { createStore } from 'redux';
const initialState = {
counter: 0
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { ...state, counter: state.counter + 1 };
case 'DECREMENT':
return { ...state, counter: state.counter - 1 };
default:
return state;
}
}
const store = createStore(reducer)
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
function Counter() {
const counter = useSelector(state => state.counter);
const dispatch = useDispatch();
return (
<div>
<p>Counter: {counter}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
</div>
)
}
export default Counter
MobX 是一个简单、透明的状态管理库,它通过可观察对象和反应式视图来管理状态。
npm install mobx mobx-react
import { makeAutoObservable } from 'mobx';
class CounterStore {
counter = 0;
constructor() {
makeAutoObservable(this);
}
increment = () => {
this.counter += 1;
}
decrement = () => {
this.counter -= 1;
}
}
const counterStore = new CounterStore()
import React from 'react';
import { observer } from 'mobx-react';
import { counterStore } from './stores/CounterStore';
const Counter = observer(() => {
return (
<div>
<p>Counter: {counterStore.counter}</p>
<button onClick={counterStore.increment}>Increment</button>
<button onClick={counterStore.decrement}>Decrement</button>
</div>
)
})
export default Counter
React 的 Context API 也可以用于状态管理,特别是在中小型应用中。虽然它不如 Redux 和 MobX 强大,但对于简单的状态管理需求已经足够。
import React, { createContext, useState } from 'react';
const CounterContext = createContext();
const CounterProvider = ({ children }) => {
const [counter, setCounter] = useState(0);
const increment = () => setCounter(counter + 1);
const decrement = () => setCounter(counter - 1);
return (
<CounterContext.Provider value={{ counter, increment, decrement }}>
{children}
</CounterContext.Provider>
)
}
export { CounterContext, CounterProvider }
import React, { useContext } from 'react';
import { CounterContext } from './CounterContext';
const Counter = () => {
const { counter, increment, decrement } = useContext(CounterContext);
return (
<div>
<p>Counter: {counter}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
)
}
export default Counter
保持组件的小型化和单一职责原则,有助于提高代码的可读性和可维护性。小型组件更容易测试和复用。
function withLoading(WrappedComponent) {
return function EnhancedComponent(props) {
if (props.isLoading) {
return <div>Loading...</div>;
}
return <WrappedComponent {...props} />;
}
}
class MouseTracker extends React.Component {
// ...
render() {
return this.props.render(this.state.mousePosition);
}
}
function App() {
return (
<MouseTracker render={mousePosition => (
<h1>The mouse position is {mousePosition.x}, {mousePosition.y}</h1>
)} />
)
}
const MyComponent = React.memo(function MyComponent(props) {
/* 渲染使用 props 的 UI */
})
function MyComponent(props) {
const memoizedValue = useMemo(() => computeExpensiveValue(props), [props]);
// ...
}
错误边界是一种 React 组件,可以捕获并处理其子组件树中任何地方抛出的 JavaScript 错误。错误边界可以防止整个应用崩溃。
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
React 不仅是一个强大的工具,也是一个不断发展的生态系统。掌握其核心概念和最佳实践对于构建高效、可维护的应用至关重要。希望本文能帮助您全面理解和运用 React,构建出优秀的用户界面。随着 React 社区的不断壮大和技术的进步,我们期待看到更多创新的应用案例。